From bf1fe99d98ee50555a76cd716c6e90f1be22dd85 Mon Sep 17 00:00:00 2001 From: colcrunch Date: Mon, 4 Jun 2018 01:45:44 -0400 Subject: [PATCH] Add Audit Log to Group Management --- .../migrations/0009_requestlog.py | 28 +++++++++++++ allianceauth/groupmanagement/models.py | 31 ++++++++++++++ .../templates/groupmanagement/audit.html | 40 +++++++++++++++++++ .../groupmanagement/groupmembership.html | 3 ++ allianceauth/groupmanagement/urls.py | 1 + allianceauth/groupmanagement/views.py | 39 +++++++++++++++++- 6 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 allianceauth/groupmanagement/migrations/0009_requestlog.py create mode 100644 allianceauth/groupmanagement/templates/groupmanagement/audit.html diff --git a/allianceauth/groupmanagement/migrations/0009_requestlog.py b/allianceauth/groupmanagement/migrations/0009_requestlog.py new file mode 100644 index 00000000..c6537fb9 --- /dev/null +++ b/allianceauth/groupmanagement/migrations/0009_requestlog.py @@ -0,0 +1,28 @@ +# Generated by Django 2.0.6 on 2018-06-04 02:45 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0009_alter_user_last_name_max_length'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('groupmanagement', '0008_remove_authgroup_permissions'), + ] + + operations = [ + migrations.CreateModel( + name='RequestLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('request_type', models.NullBooleanField(default=0)), + ('request_info', models.CharField(max_length=254)), + ('action', models.BooleanField(default=0)), + ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')), + ('request_actor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/allianceauth/groupmanagement/models.py b/allianceauth/groupmanagement/models.py index 3e389e1c..4e93a090 100644 --- a/allianceauth/groupmanagement/models.py +++ b/allianceauth/groupmanagement/models.py @@ -23,6 +23,37 @@ class GroupRequest(models.Model): return self.user.username + ":" + self.group.name +class RequestLog(models.Model): + request_type = models.NullBooleanField(default=0) + group = models.ForeignKey(Group, on_delete=models.CASCADE) + request_info = models.CharField(max_length=254) + action = models.BooleanField(default=0) + request_actor = models.ForeignKey(User, on_delete=models.CASCADE) + + def requestor(self): + return self.request_info.split(":")[0] + + def type_to_str(self): + if self.request_type is None: + return "Removed" + elif self.request_type is True: + return "Leave" + elif self.request_type is False: + return "Join" + + def action_to_str(self): + if self.action is True: + return "Accept" + elif self.action is False: + return "Reject" + + def req_char(self): + usr = self.requestor() + user = User.objects.get(username=usr) + return user.profile.main_character + + + class AuthGroup(models.Model): """ Extends Django Group model with a one-to-one field diff --git a/allianceauth/groupmanagement/templates/groupmanagement/audit.html b/allianceauth/groupmanagement/templates/groupmanagement/audit.html new file mode 100644 index 00000000..c5f26892 --- /dev/null +++ b/allianceauth/groupmanagement/templates/groupmanagement/audit.html @@ -0,0 +1,40 @@ +{% extends "allianceauth/base.html" %} +{% load staticfiles %} +{% load i18n %} + +{% block page_title %}{{ group }} {% trans "Audit Log" %}{% endblock page_title %} +{% block extra_css %}{% endblock extra_css %} + +{% block content %} +
+
+ {% include 'groupmanagement/menu.html' %} +
+ {% if entries %} +

{{ group }} Audit Log

+ + + + + + + + + + {% for entry in entries %} + + + + + + + + + {% endfor %} +
{% trans "Requestor" %}{% trans "Main Character" %}{% trans "Group" %}{% trans "Type" %}{% trans "Action" %}{% trans "Actor" %}
{{ entry.requestor }}{{ entry.req_char }}{{ entry.group }}{{ entry.type_to_str }}{{ entry.action_to_str }}{{ entry.request_actor }}
+ {% else %} +
{% trans "No entries found." %}
+ {% endif %} +
+
+{% endblock content %} diff --git a/allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html b/allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html index 7384c23a..5e47a0be 100644 --- a/allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html +++ b/allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html @@ -41,6 +41,9 @@ title="{% trans "View Members" %}"> + + + {% endfor %} diff --git a/allianceauth/groupmanagement/urls.py b/allianceauth/groupmanagement/urls.py index 37de11fe..3533df01 100644 --- a/allianceauth/groupmanagement/urls.py +++ b/allianceauth/groupmanagement/urls.py @@ -12,6 +12,7 @@ urlpatterns = [ name='membership'), url(r'^membership/(\w+)/$', views.group_membership_list, name='membership_list'), + url(r'^membership/(\w+)/audit/', views.group_membership_audit, name="audit_log"), url(r'^membership/(\w+)/remove/(\w+)/$', views.group_membership_remove, name='membership_remove'), url(r'^request_add/(\w+)', views.group_request_add, diff --git a/allianceauth/groupmanagement/views.py b/allianceauth/groupmanagement/views.py index ee564a2d..2ee8438a 100755 --- a/allianceauth/groupmanagement/views.py +++ b/allianceauth/groupmanagement/views.py @@ -10,7 +10,7 @@ from django.http import Http404 from django.shortcuts import render, redirect, get_object_or_404 from django.utils.translation import ugettext_lazy as _ from .managers import GroupManager -from .models import GroupRequest +from .models import GroupRequest, RequestLog from allianceauth.notifications import notify @@ -65,6 +65,32 @@ def group_membership(request): return render(request, 'groupmanagement/groupmembership.html', context=render_items) +@login_required +@user_passes_test(GroupManager.can_manage_groups) +def group_membership_audit(request, group_id): + logger.debug("group_management_audit called by user %s" % request.user) + group = get_object_or_404(Group, id=group_id) + try: + + # Check its a joinable group i.e. not corp or internal + # And the user has permission to manage it + if not GroupManager.joinable_group(group) or not GroupManager.can_manage_group(request.user, group): + logger.warning("User %s attempted to view the membership of group %s but permission was denied" % + (request.user, group_id)) + raise PermissionDenied + + except ObjectDoesNotExist: + raise Http404("Group does not exist") + + entries = RequestLog.objects.filter(group=group) + + render_items = {'entries': entries, 'group': group.name} + + return render(request, 'groupmanagement/audit.html', context=render_items) + + + + @login_required @user_passes_test(GroupManager.can_manage_groups) def group_membership_list(request, group_id): @@ -112,6 +138,9 @@ def group_membership_remove(request, group_id, user_id): try: user = group.user_set.get(id=user_id) + request_info = user.username + ":" + group.name + log = RequestLog(request_type=None,group=group,request_info=request_info,action=1,request_actor=request.user) + log.save() # Remove group from user user.groups.remove(group) logger.info("User %s removed user %s from group %s" % (request.user, user, group)) @@ -139,6 +168,8 @@ def group_accept_request(request, group_request_id): group_request.user.groups.add(group) group_request.user.save() + log = RequestLog(request_type=group_request.leave_request,group=group,request_info=group_request.__str__(),action=1,request_actor=request.user) + log.save() group_request.delete() logger.info("User %s accepted group request from user %s to group %s" % ( request.user, group_request.user, group_request.group.name)) @@ -172,6 +203,8 @@ def group_reject_request(request, group_request_id): if group_request: logger.info("User %s rejected group request from user %s to group %s" % ( request.user, group_request.user, group_request.group.name)) + log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=0,request_actor=request.user) + log.save() group_request.delete() notify(group_request.user, "Group Application Rejected", level="danger", message="Your application to %s has been rejected." % group_request.group) @@ -204,6 +237,8 @@ def group_leave_accept_request(request, group_request_id): group, created = Group.objects.get_or_create(name=group_request.group.name) group_request.user.groups.remove(group) group_request.user.save() + log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=1,request_actor=request.user) + log.save() group_request.delete() logger.info("User %s accepted group leave request from user %s to group %s" % ( request.user, group_request.user, group_request.group.name)) @@ -236,6 +271,8 @@ def group_leave_reject_request(request, group_request_id): raise PermissionDenied if group_request: + log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=0,request_actor=request.user) + log.save() group_request.delete() logger.info("User %s rejected group leave request from user %s for group %s" % ( request.user, group_request.user, group_request.group.name))