diff --git a/netbox/extras/migrations/0005_auto_20160524_1324.py b/netbox/extras/migrations/0005_auto_20160524_1324.py new file mode 100644 index 000000000..d1c214a75 --- /dev/null +++ b/netbox/extras/migrations/0005_auto_20160524_1324.py @@ -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), + ), + ] diff --git a/netbox/extras/models.py b/netbox/extras/models.py index 9dba10bd4..a3396124e 100644 --- a/netbox/extras/models.py +++ b/netbox/extras/models.py @@ -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('') + elif self.action in [ACTION_EDIT, ACTION_BULK_EDIT]: + return mark_safe('') + elif self.action in [ACTION_DELETE, ACTION_BULK_DELETE]: + return mark_safe('') + else: + return '' diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index e0ce6803c..0197a7dd5 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -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] }) diff --git a/netbox/templates/home.html b/netbox/templates/home.html index ccdb2cbd2..9609c9023 100644 --- a/netbox/templates/home.html +++ b/netbox/templates/home.html @@ -47,100 +47,104 @@
-
-
-
- DCIM +
+
+
+
+
+ DCIM +
+
+
+ {{ stats.site_count }} +

Sites

+

Geographic locations

+
+
+ {{ stats.rack_count }} +

Racks

+

Equipment racks, optionally organized by group

+
+
+ {{ stats.device_count }} +

Devices

+

Rack-mounted network equipment, servers, and other devices

+
+
+

Connections

+ {{ stats.interface_connections_count }} +

Interfaces

+ {{ stats.console_connections_count }} +

Console

+ {{ stats.power_connections_count }} +

Power

+
+
+
+ {% if perms.secrets %} +
+
+ Secrets +
+
+
+ {{ stats.secret_count }} +

Secrets

+

Sensitive data (such as passwords) which has been stored securely

+
+
+
+ {% endif %}
-
-
- {{ stats.site_count }} -

Sites

-

Geographic locations

+
+
+
+ IPAM +
+
+
+ {{ stats.aggregate_count }} +

Aggregates

+

Top-level IP allocations

+
+
+ {{ stats.prefix_count }} +

Prefixes

+

IPv4 and IPv6 network assignments

+
+
+ {{ stats.ipaddress_count }} +

IP Addresses

+

Individual IPv4 and IPv6 addresses

+
+
+ {{ stats.vlan_count }} +

VLANs

+

Layer two domains, identified by VLAN ID

+
+
-
- {{ stats.rack_count }} -

Racks

-

Equipment racks, optionally organized by group

-
-
- {{ stats.device_count }} -

Devices

-

Rack-mounted network equipment, servers, and other devices

-
-
-

Connections

- {{ stats.interface_connections_count }} -

Interfaces

- {{ stats.console_connections_count }} -

Console

- {{ stats.power_connections_count }} -

Power

-
-
-
- {% if perms.secrets %} -
-
- Secrets -
-
-
- {{ stats.secret_count }} -

Secrets

-

Sensitive data (such as passwords) which has been stored securely

+
+
+ Circuits +
+
+
+ {{ stats.provider_count }} +

Providers

+

Organizations which provide circuit connectivity

+
+
+ {{ stats.circuit_count }} +

Circuits

+

Communication links for Internet transit, peering, and other services

+
- {% endif %} -
-
-
-
- IPAM -
-
-
- {{ stats.aggregate_count }} -

Aggregates

-

Top-level IP allocations

-
-
- {{ stats.prefix_count }} -

Prefixes

-

IPv4 and IPv6 network assignments

-
-
- {{ stats.ipaddress_count }} -

IP Addresses

-

Individual IPv4 and IPv6 addresses

-
-
- {{ stats.vlan_count }} -

VLANs

-

Layer two domains, identified by VLAN ID

-
-
-
-
-
- Circuits -
-
-
- {{ stats.provider_count }} -

Providers

-

Organizations which provide circuit connectivity

-
-
- {{ stats.circuit_count }} -

Circuits

-

Communication links for Internet transit, peering, and other services

-
-
-
+
Recent Activity @@ -150,7 +154,7 @@ {{ a.time|date:"Y-m-d H:i" }} {{ a.user }} - {{ a.message|safe }} + {{ a.icon }} {{ a.message|safe }} {% endfor %} diff --git a/netbox/templates/users/inc/profile_nav.html b/netbox/templates/users/inc/profile_nav.html index f21db3e1d..c5b1791bb 100644 --- a/netbox/templates/users/inc/profile_nav.html +++ b/netbox/templates/users/inc/profile_nav.html @@ -2,4 +2,5 @@ Profile Change Password User Key + Recent Activity diff --git a/netbox/templates/users/recent_activity.html b/netbox/templates/users/recent_activity.html new file mode 100644 index 000000000..76b8c3f54 --- /dev/null +++ b/netbox/templates/users/recent_activity.html @@ -0,0 +1,35 @@ +{% extends '_base.html' %} +{% load form_helpers %} + +{% block title %}Recent Activity{% endblock %} + +{% block content %} +
+
+

Recent Activity

+
+
+
+
+ {% include 'users/inc/profile_nav.html' with active_tab="recent_activity" %} +
+
+ + + + + + + + + {% for action in recent_activity %} + + + + + {% endfor %} + +
TimeAction
{{ action.time|date:"Y-m-d H:i" }}{{ action.icon }} {{ action.message|safe }}
+
+
+{% endblock %} diff --git a/netbox/users/urls.py b/netbox/users/urls.py index 4e38050f1..d33d14beb 100644 --- a/netbox/users/urls.py +++ b/netbox/users/urls.py @@ -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'), ] diff --git a/netbox/users/views.py b/netbox/users/views.py index 0337833b8..7a01539b7 100644 --- a/netbox/users/views.py +++ b/netbox/users/views.py @@ -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] + })