mirror of
				https://github.com/netbox-community/netbox.git
				synced 2024-05-10 07:54:54 +00:00 
			
		
		
		
	Improved UserAction display
This commit is contained in:
		
							
								
								
									
										22
									
								
								netbox/extras/migrations/0005_auto_20160524_1324.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								netbox/extras/migrations/0005_auto_20160524_1324.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.9.5 on 2016-05-24 13:24
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('extras', '0004_useraction'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='useraction',
 | 
			
		||||
            name='user',
 | 
			
		||||
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='actions', to=settings.AUTH_USER_MODEL),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -3,6 +3,7 @@ from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.http import HttpResponse
 | 
			
		||||
from django.template import Template, Context
 | 
			
		||||
from django.utils.safestring import mark_safe
 | 
			
		||||
 | 
			
		||||
from dcim.models import Site
 | 
			
		||||
 | 
			
		||||
@@ -156,7 +157,7 @@ class UserAction(models.Model):
 | 
			
		||||
    A record of an action (add, edit, or delete) performed on an object by a User.
 | 
			
		||||
    """
 | 
			
		||||
    time = models.DateTimeField(auto_now_add=True, editable=False)
 | 
			
		||||
    user = models.ForeignKey(User, on_delete=models.CASCADE)
 | 
			
		||||
    user = models.ForeignKey(User, related_name='actions', on_delete=models.CASCADE)
 | 
			
		||||
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
 | 
			
		||||
    object_id = models.PositiveIntegerField(blank=True, null=True)
 | 
			
		||||
    action = models.PositiveSmallIntegerField(choices=ACTION_CHOICES)
 | 
			
		||||
@@ -166,3 +167,18 @@ class UserAction(models.Model):
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        ordering = ['-time']
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        if self.message:
 | 
			
		||||
            return ' '.join([self.user, self.message])
 | 
			
		||||
        return ' '.join([self.user, self.get_action_display(), self.content_type])
 | 
			
		||||
 | 
			
		||||
    def icon(self):
 | 
			
		||||
        if self.action in [ACTION_CREATE, ACTION_IMPORT]:
 | 
			
		||||
            return mark_safe('<i class="glyphicon glyphicon-plus text-success"></i>')
 | 
			
		||||
        elif self.action in [ACTION_EDIT, ACTION_BULK_EDIT]:
 | 
			
		||||
            return mark_safe('<i class="glyphicon glyphicon-pencil text-warning"></i>')
 | 
			
		||||
        elif self.action in [ACTION_DELETE, ACTION_BULK_DELETE]:
 | 
			
		||||
            return mark_safe('<i class="glyphicon glyphicon-remove text-danger"></i>')
 | 
			
		||||
        else:
 | 
			
		||||
            return ''
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ def home(request):
 | 
			
		||||
 | 
			
		||||
    return render(request, 'home.html', {
 | 
			
		||||
        'stats': stats,
 | 
			
		||||
        'recent_activity': UserAction.objects.all()[:20]
 | 
			
		||||
        'recent_activity': UserAction.objects.all()[:15]
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,100 +47,104 @@
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <div class="col-md-4">
 | 
			
		||||
        <div class="panel panel-default">
 | 
			
		||||
            <div class="panel-heading">
 | 
			
		||||
                <strong>DCIM</strong>
 | 
			
		||||
    <div class="col-md-7">
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="panel panel-default">
 | 
			
		||||
                    <div class="panel-heading">
 | 
			
		||||
                        <strong>DCIM</strong>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="list-group">
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.site_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'dcim:site_list' %}">Sites</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">Geographic locations</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.rack_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'dcim:rack_list' %}">Racks</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">Equipment racks, optionally organized by group</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.device_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'dcim:device_list' %}">Devices</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">Rack-mounted network equipment, servers, and other devices</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <h4 class="list-group-item-heading">Connections</h4>
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.interface_connections_count }}</span>
 | 
			
		||||
                            <p style="padding-left: 20px;"><a href="{% url 'dcim:interface_connections_list' %}">Interfaces</a></p>
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.console_connections_count }}</span>
 | 
			
		||||
                            <p style="padding-left: 20px;"><a href="{% url 'dcim:console_connections_list' %}">Console</a></p>
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.power_connections_count }}</span>
 | 
			
		||||
                            <p class="list-group-item-text" style="padding-left: 20px;"><a href="{% url 'dcim:power_connections_list' %}">Power</a></p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                {% if perms.secrets %}
 | 
			
		||||
                    <div class="panel panel-default">
 | 
			
		||||
                        <div class="panel-heading">
 | 
			
		||||
                            <strong>Secrets</strong>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="list-group">
 | 
			
		||||
                            <div class="list-group-item">
 | 
			
		||||
                                <span class="badge pull-right">{{ stats.secret_count }}</span>
 | 
			
		||||
                                <h4 class="list-group-item-heading"><a href="{% url 'secrets:secret_list' %}">Secrets</a></h4>
 | 
			
		||||
                                <p class="list-group-item-text text-muted">Sensitive data (such as passwords) which has been stored securely</p>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="list-group">
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.site_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'dcim:site_list' %}">Sites</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">Geographic locations</p>
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="panel panel-default">
 | 
			
		||||
                    <div class="panel-heading">
 | 
			
		||||
                        <strong>IPAM</strong>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="list-group">
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.aggregate_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'ipam:aggregate_list' %}">Aggregates</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">Top-level IP allocations</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.prefix_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'ipam:prefix_list' %}">Prefixes</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">IPv4 and IPv6 network assignments</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.ipaddress_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'ipam:ipaddress_list' %}">IP Addresses</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">Individual IPv4 and IPv6 addresses</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.vlan_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'ipam:vlan_list' %}">VLANs</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">Layer two domains, identified by VLAN ID</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.rack_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'dcim:rack_list' %}">Racks</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">Equipment racks, optionally organized by group</p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.device_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'dcim:device_list' %}">Devices</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">Rack-mounted network equipment, servers, and other devices</p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <h4 class="list-group-item-heading">Connections</h4>
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.interface_connections_count }}</span>
 | 
			
		||||
                    <p style="padding-left: 20px;"><a href="{% url 'dcim:interface_connections_list' %}">Interfaces</a></p>
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.console_connections_count }}</span>
 | 
			
		||||
                    <p style="padding-left: 20px;"><a href="{% url 'dcim:console_connections_list' %}">Console</a></p>
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.power_connections_count }}</span>
 | 
			
		||||
                    <p class="list-group-item-text" style="padding-left: 20px;"><a href="{% url 'dcim:power_connections_list' %}">Power</a></p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        {% if perms.secrets %}
 | 
			
		||||
            <div class="panel panel-default">
 | 
			
		||||
                <div class="panel-heading">
 | 
			
		||||
                    <strong>Secrets</strong>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="list-group">
 | 
			
		||||
                    <div class="list-group-item">
 | 
			
		||||
                        <span class="badge pull-right">{{ stats.secret_count }}</span>
 | 
			
		||||
                        <h4 class="list-group-item-heading"><a href="{% url 'secrets:secret_list' %}">Secrets</a></h4>
 | 
			
		||||
                        <p class="list-group-item-text text-muted">Sensitive data (such as passwords) which has been stored securely</p>
 | 
			
		||||
                <div class="panel panel-default">
 | 
			
		||||
                    <div class="panel-heading">
 | 
			
		||||
                        <strong>Circuits</strong>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="list-group">
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.provider_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'circuits:provider_list' %}">Providers</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">Organizations which provide circuit connectivity</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="list-group-item">
 | 
			
		||||
                            <span class="badge pull-right">{{ stats.circuit_count }}</span>
 | 
			
		||||
                            <h4 class="list-group-item-heading"><a href="{% url 'circuits:circuit_list' %}">Circuits</a></h4>
 | 
			
		||||
                            <p class="list-group-item-text text-muted">Communication links for Internet transit, peering, and other services</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col-md-4">
 | 
			
		||||
        <div class="panel panel-default">
 | 
			
		||||
            <div class="panel-heading">
 | 
			
		||||
                <strong>IPAM</strong>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="list-group">
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.aggregate_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'ipam:aggregate_list' %}">Aggregates</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">Top-level IP allocations</p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.prefix_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'ipam:prefix_list' %}">Prefixes</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">IPv4 and IPv6 network assignments</p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.ipaddress_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'ipam:ipaddress_list' %}">IP Addresses</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">Individual IPv4 and IPv6 addresses</p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.vlan_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'ipam:vlan_list' %}">VLANs</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">Layer two domains, identified by VLAN ID</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="panel panel-default">
 | 
			
		||||
            <div class="panel-heading">
 | 
			
		||||
                <strong>Circuits</strong>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="list-group">
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.provider_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'circuits:provider_list' %}">Providers</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">Organizations which provide circuit connectivity</p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="list-group-item">
 | 
			
		||||
                    <span class="badge pull-right">{{ stats.circuit_count }}</span>
 | 
			
		||||
                    <h4 class="list-group-item-heading"><a href="{% url 'circuits:circuit_list' %}">Circuits</a></h4>
 | 
			
		||||
                    <p class="list-group-item-text text-muted">Communication links for Internet transit, peering, and other services</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col-md-4">
 | 
			
		||||
    <div class="col-md-5">
 | 
			
		||||
        <div class="panel panel-default">
 | 
			
		||||
            <div class="panel-heading">
 | 
			
		||||
                <strong>Recent Activity</strong>
 | 
			
		||||
@@ -150,7 +154,7 @@
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td>{{ a.time|date:"Y-m-d H:i" }}</td>
 | 
			
		||||
                        <td>{{ a.user }}</td>
 | 
			
		||||
                        <td>{{ a.message|safe }}</td>
 | 
			
		||||
                        <td>{{ a.icon }} {{ a.message|safe }}</td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
            </table>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,4 +2,5 @@
 | 
			
		||||
    <li{% ifequal active_tab "profile" %} class="active"{% endifequal %}><a href="{% url 'users:profile' %}">Profile</a></li>
 | 
			
		||||
    <li{% ifequal active_tab "change_password" %} class="active"{% endifequal %}><a href="{% url 'users:change_password' %}">Change Password</a></li>
 | 
			
		||||
    <li{% ifequal active_tab "userkey" %} class="active"{% endifequal %}><a href="{% url 'users:userkey' %}">User Key</a></li>
 | 
			
		||||
    <li{% ifequal active_tab "recent_activity" %} class="active"{% endifequal %}><a href="{% url 'users:recent_activity' %}">Recent Activity</a></li>
 | 
			
		||||
</ul>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										35
									
								
								netbox/templates/users/recent_activity.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								netbox/templates/users/recent_activity.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
{% extends '_base.html' %}
 | 
			
		||||
{% load form_helpers %}
 | 
			
		||||
 | 
			
		||||
{% block title %}Recent Activity{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <div class="col-md-8 col-md-offset-2">
 | 
			
		||||
        <h1>Recent Activity</h1>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <div class="col-md-2 col-md-offset-2">
 | 
			
		||||
        {% include 'users/inc/profile_nav.html' with active_tab="recent_activity" %}
 | 
			
		||||
    </div>
 | 
			
		||||
	<div class="col-md-6">
 | 
			
		||||
        <table class="table table-hover">
 | 
			
		||||
            <thead>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th>Time</th>
 | 
			
		||||
                    <th>Action</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </thead>
 | 
			
		||||
            <tbody>
 | 
			
		||||
                {% for action in recent_activity %}
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td>{{ action.time|date:"Y-m-d H:i" }}</td>
 | 
			
		||||
                        <td>{{ action.icon }} {{ action.message|safe }}</td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
            </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@@ -10,5 +10,6 @@ urlpatterns = [
 | 
			
		||||
    url(r'^profile/password/$', views.change_password, name='change_password'),
 | 
			
		||||
    url(r'^profile/user-key/$', views.userkey, name='userkey'),
 | 
			
		||||
    url(r'^profile/user-key/edit/$', views.userkey_edit, name='userkey_edit'),
 | 
			
		||||
    url(r'^profile/recent-activity/$', views.recent_activity, name='recent_activity'),
 | 
			
		||||
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -116,3 +116,11 @@ def userkey_edit(request):
 | 
			
		||||
        'userkey': userkey,
 | 
			
		||||
        'form': form,
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required()
 | 
			
		||||
def recent_activity(request):
 | 
			
		||||
 | 
			
		||||
    return render(request, 'users/recent_activity.html', {
 | 
			
		||||
        'recent_activity': request.user.actions.all()[:50]
 | 
			
		||||
    })
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user