diff --git a/cotisations/models.py b/cotisations/models.py index 2db945b4..6be735f7 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -6,6 +6,8 @@ from dateutil.relativedelta import relativedelta from django.core.validators import MinValueValidator class Facture(models.Model): + PRETTY_NAME = "Factures émises" + user = models.ForeignKey('users.User', on_delete=models.PROTECT) paiement = models.ForeignKey('Paiement', on_delete=models.PROTECT) banque = models.ForeignKey('Banque', on_delete=models.PROTECT, blank=True, null=True) @@ -40,6 +42,8 @@ def facture_post_delete(sender, **kwargs): #user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) class Vente(models.Model): + PRETTY_NAME = "Ventes effectuées" + facture = models.ForeignKey('Facture', on_delete=models.CASCADE) number = models.IntegerField(validators=[MinValueValidator(1)]) name = models.CharField(max_length=255) @@ -74,6 +78,8 @@ def vente_post_delete(sender, **kwargs): #user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) class Article(models.Model): + PRETTY_NAME = "Articles en vente" + name = models.CharField(max_length=255) prix = models.DecimalField(max_digits=5, decimal_places=2) iscotisation = models.BooleanField() @@ -83,18 +89,24 @@ class Article(models.Model): return self.name class Banque(models.Model): + PRETTY_NAME = "Banques enregistrées" + name = models.CharField(max_length=255) def __str__(self): return self.name class Paiement(models.Model): + PRETTY_NAME = "Moyens de paiement" + moyen = models.CharField(max_length=255) def __str__(self): return self.moyen class Cotisation(models.Model): + PRETTY_NAME = "Cotisations" + vente = models.OneToOneField('Vente', on_delete=models.CASCADE, null=True) date_start = models.DateTimeField() date_end = models.DateTimeField() diff --git a/logs/templates/logs/aff_actions.html b/logs/templates/logs/aff_actions.html index e1ee5734..798f4224 100644 --- a/logs/templates/logs/aff_actions.html +++ b/logs/templates/logs/aff_actions.html @@ -12,6 +12,7 @@ Modification par Date de modification Commentaire + {% for revision in revisions_list %} @@ -21,6 +22,7 @@ {{ revision.user }} {{ revision.date_created }} {{ revision.comment }} - + {% if is_bureau %}Annuler

{% endif %} + {% endfor %} diff --git a/logs/templates/logs/aff_stats_models.html b/logs/templates/logs/aff_stats_models.html new file mode 100644 index 00000000..8d3e2b9d --- /dev/null +++ b/logs/templates/logs/aff_stats_models.html @@ -0,0 +1,17 @@ + {% for key, stats in stats_list.items %} + +

Statistiques de l'ensemble {{ key }}

+ + + + + + + {% for key, stat in stats.items %} + + + + + {% endfor %} +
Type d'objetNombre d'entrée stockées
{{ stat.0 }}{{ stat.1 }}
+ {% endfor %} diff --git a/logs/templates/logs/delete.html b/logs/templates/logs/delete.html new file mode 100644 index 00000000..1e2c8373 --- /dev/null +++ b/logs/templates/logs/delete.html @@ -0,0 +1,16 @@ +{% extends "logs/sidebar.html" %} +{% load bootstrap3 %} + +{% block title %}Supression d'action{% endblock %} + +{% block content %} + +
+ {% csrf_token %} +

Attention, voulez-vous vraiment annuler cette action {{ objet_name }} ( {{ objet }} ) ?

+ {% bootstrap_button "Confirmer" button_type="submit" icon="trash" %} +
+
+
+
+{% endblock %} diff --git a/logs/templates/logs/sidebar.html b/logs/templates/logs/sidebar.html index aa868933..fd1e35f3 100644 --- a/logs/templates/logs/sidebar.html +++ b/logs/templates/logs/sidebar.html @@ -2,5 +2,6 @@ {% block sidebar %} {% if is_cableur %} +

Statistiques base de donnée

{% endif %} {% endblock %} diff --git a/logs/templates/logs/stats_models.html b/logs/templates/logs/stats_models.html new file mode 100644 index 00000000..0195fd48 --- /dev/null +++ b/logs/templates/logs/stats_models.html @@ -0,0 +1,12 @@ +{% extends "logs/sidebar.html" %} +{% load bootstrap3 %} + +{% block title %}Statistiques des objets base de données{% endblock %} + +{% block content %} +

Statistiques bdd

+ {% include "logs/aff_stats_models.html" with stats_list=stats_list %} +
+
+
+ {% endblock %} diff --git a/logs/urls.py b/logs/urls.py index a3780aa2..8ed34e1d 100644 --- a/logs/urls.py +++ b/logs/urls.py @@ -4,4 +4,6 @@ from . import views urlpatterns = [ url(r'^$', views.index, name='index'), + url(r'^revert_action/(?P[0-9]+)$', views.revert_action, name='revert-action'), + url(r'^stats_models/$', views.stats_models, name='stats-models'), ] diff --git a/logs/views.py b/logs/views.py index fd55a715..00e04af8 100644 --- a/logs/views.py +++ b/logs/views.py @@ -16,8 +16,18 @@ from django.db import transaction from reversion.models import Revision from reversion.models import Version +from users.models import User, ServiceUser, Right, School, ListRight, ListShell, Ban, Whitelist +from cotisations.models import Facture, Vente, Article, Banque, Paiement, Cotisation +from machines.models import Machine, MachineType, IpType, Extension, Interface, Alias, IpList +from topologie.models import Switch, Port, Room + from re2o.settings import PAGINATION_NUMBER, PAGINATION_LARGE_NUMBER +def form(ctx, template, request): + c = ctx + c.update(csrf(request)) + return render_to_response(template, c, context_instance=RequestContext(request)) + @login_required @permission_required('cableur') def index(request): @@ -34,3 +44,55 @@ def index(request): revisions = paginator.page(paginator.num_pages) return render(request, 'logs/index.html', {'revisions_list': revisions}) +@login_required +@permission_required('bureau') +def revert_action(request, revision_id): + """ Annule l'action en question """ + try: + revision = Revision.objects.get(id=revision_id) + except Revision.DoesNotExist: + messages.error(request, u"Revision inexistante" ) + if request.method == "POST": + revision.revert() + messages.success(request, "L'action a été supprimée") + return redirect("/logs/") + return form({'objet': revision, 'objet_name': revision.__class__.__name__ }, 'logs/delete.html', request) + +@login_required +@permission_required('cableur') +def stats_models(request): + stats = { + 'Users' : { + 'users' : [User.PRETTY_NAME, User.objects.count()], + 'serviceuser' : [ServiceUser.PRETTY_NAME, ServiceUser.objects.count()], + 'right' : [Right.PRETTY_NAME, Right.objects.count()], + 'school' : [School.PRETTY_NAME, School.objects.count()], + 'listright' : [ListRight.PRETTY_NAME, ListRight.objects.count()], + 'listshell' : [ListShell.PRETTY_NAME, ListShell.objects.count()], + 'ban' : [Ban.PRETTY_NAME, Ban.objects.count()], + 'whitelist' : [Whitelist.PRETTY_NAME, Whitelist.objects.count()] + }, + 'Cotisations' : { + 'factures' : [Facture.PRETTY_NAME, Facture.objects.count()], + 'vente' : [Vente.PRETTY_NAME, Vente.objects.count()], + 'cotisation' : [Cotisation.PRETTY_NAME, Cotisation.objects.count()], + 'article' : [Article.PRETTY_NAME, Article.objects.count()], + 'banque' : [Banque.PRETTY_NAME, Banque.objects.count()], + 'cotisation' : [Cotisation.PRETTY_NAME, Cotisation.objects.count()], + }, + 'Machines' : { + 'machine' : [Machine.PRETTY_NAME, Machine.objects.count()], + 'typemachine' : [MachineType.PRETTY_NAME, MachineType.objects.count()], + 'typeip' : [IpType.PRETTY_NAME, IpType.objects.count()], + 'extension' : [Extension.PRETTY_NAME, Extension.objects.count()], + 'interface' : [Interface.PRETTY_NAME, Interface.objects.count()], + 'alias' : [Alias.PRETTY_NAME, Alias.objects.count()], + 'iplist' : [IpList.PRETTY_NAME, IpList.objects.count()], + }, + 'Topologie' : { + 'switch' : [Switch.PRETTY_NAME, Switch.objects.count()], + 'port' : [Port.PRETTY_NAME, Port.objects.count()], + 'chambre' : [Room.PRETTY_NAME, Room.objects.count()], + }, + } + return render(request, 'logs/stats_models.html', {'stats_list': stats}) diff --git a/machines/admin.py b/machines/admin.py index 7ee8cde1..6423e1c1 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin from reversion.admin import VersionAdmin -from .models import IpType, Machine, MachineType, IpList, Interface, Extension +from .models import IpType, Machine, MachineType, Alias, IpList, Interface, Extension class MachineAdmin(VersionAdmin): list_display = ('user','name','active') @@ -22,9 +22,13 @@ class IpListAdmin(VersionAdmin): class InterfaceAdmin(VersionAdmin): list_display = ('machine','type','dns','mac_address','ipv4','details') +class AliasAdmin(VersionAdmin): + list_display = ('interface_parent', 'alias') + admin.site.register(Machine, MachineAdmin) admin.site.register(MachineType, MachineTypeAdmin) admin.site.register(IpType, IpTypeAdmin) admin.site.register(Extension, ExtensionAdmin) admin.site.register(IpList, IpListAdmin) admin.site.register(Interface, InterfaceAdmin) +admin.site.register(Alias, AliasAdmin) diff --git a/machines/forms.py b/machines/forms.py index d2818b0d..5a9e3395 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -1,6 +1,6 @@ from django.forms import ModelForm, Form, ValidationError from django import forms -from .models import Machine, Interface, IpList, MachineType, Extension, IpType +from .models import Alias, Machine, Interface, IpList, MachineType, Extension, IpType class EditMachineForm(ModelForm): class Meta: @@ -59,6 +59,15 @@ class BaseEditInterfaceForm(EditInterfaceForm): self.fields['type'].queryset = MachineType.objects.filter(ip_type=IpType.objects.filter(need_infra=False)) self.fields['ipv4'].queryset = IpList.objects.filter(ip_type=IpType.objects.filter(need_infra=False)) +class NewAliasForm(ModelForm): + class Meta: + model = Alias + fields = ['alias'] + +class EditAliasFullForm(NewAliasForm): + class Meta(NewAliasForm.Meta): + fields = '__all__' + class MachineTypeForm(ModelForm): class Meta: model = MachineType diff --git a/machines/migrations/0027_alias.py b/machines/migrations/0027_alias.py new file mode 100644 index 00000000..fac2a108 --- /dev/null +++ b/machines/migrations/0027_alias.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0026_auto_20161026_1348'), + ] + + operations = [ + migrations.CreateModel( + name='Alias', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), + ('alias', models.CharField(max_length=255, help_text='Obligatoire et unique, ne doit pas comporter de points', unique=True)), + ('interface_parent', models.ForeignKey(to='machines.Interface')), + ], + ), + ] diff --git a/machines/models.py b/machines/models.py index 31d1a406..7d083e09 100644 --- a/machines/models.py +++ b/machines/models.py @@ -8,6 +8,8 @@ from re2o.settings import MAIN_EXTENSION class Machine(models.Model): + PRETTY_NAME = "Machine" + user = models.ForeignKey('users.User', on_delete=models.PROTECT) name = models.CharField(max_length=255, help_text="Optionnel", blank=True, null=True) active = models.BooleanField(default=True) @@ -16,6 +18,8 @@ class Machine(models.Model): return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name) class MachineType(models.Model): + PRETTY_NAME = "Type de machine" + type = models.CharField(max_length=255) ip_type = models.ForeignKey('IpType', on_delete=models.PROTECT, blank=True, null=True) @@ -23,6 +27,8 @@ class MachineType(models.Model): return self.type class IpType(models.Model): + PRETTY_NAME = "Type d'ip" + type = models.CharField(max_length=255) extension = models.ForeignKey('Extension', on_delete=models.PROTECT) need_infra = models.BooleanField(default=False) @@ -31,12 +37,16 @@ class IpType(models.Model): return self.type class Extension(models.Model): + PRETTY_NAME = "Extensions dns" + name = models.CharField(max_length=255) def __str__(self): return self.name class Interface(models.Model): + PRETTY_NAME = "Interface" + ipv4 = models.OneToOneField('IpList', on_delete=models.PROTECT, blank=True, null=True) #ipv6 = models.GenericIPAddressField(protocol='IPv6', null=True) mac_address = MACAddressField(integer=False, unique=True) @@ -54,7 +64,18 @@ class Interface(models.Model): def __str__(self): return self.dns +class Alias(models.Model): + PRETTY_NAME = "Alias dns" + + interface_parent = models.ForeignKey('Interface', on_delete=models.CASCADE) + alias = models.CharField(help_text="Obligatoire et unique, ne doit pas comporter de points", max_length=255, unique=True) + + def __str__(self): + return self.alias + class IpList(models.Model): + PRETTY_NAME = "Addresses ipv4" + ipv4 = models.GenericIPAddressField(protocol='IPv4', unique=True) ip_type = models.ForeignKey('IpType', on_delete=models.PROTECT) diff --git a/machines/views.py b/machines/views.py index 5561c89e..91a250e1 100644 --- a/machines/views.py +++ b/machines/views.py @@ -20,7 +20,7 @@ from reversion import revisions as reversion import re from .forms import NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm, MachineTypeForm, DelMachineTypeForm, ExtensionForm, DelExtensionForm, BaseEditInterfaceForm, BaseEditMachineForm -from .forms import IpTypeForm, DelIpTypeForm +from .forms import IpTypeForm, DelIpTypeForm, NewAliasForm, EditAliasFullForm from .models import IpType, Machine, Interface, IpList, MachineType, Extension from users.models import User from re2o.settings import PAGINATION_NUMBER, PAGINATION_LARGE_NUMBER diff --git a/topologie/models.py b/topologie/models.py index ceb06345..0e14fdf7 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -16,6 +16,8 @@ def clean_port_related(port): related_port.save() class Switch(models.Model): + PRETTY_NAME = "Switch / Commutateur" + switch_interface = models.OneToOneField('machines.Interface', on_delete=models.CASCADE) location = models.CharField(max_length=255) number = models.IntegerField() @@ -25,6 +27,8 @@ class Switch(models.Model): return str(self.location) class Port(models.Model): + PRETTY_NAME = "Port de switch" + switch = models.ForeignKey('Switch', related_name="ports") port = models.IntegerField() room = models.ForeignKey('Room', on_delete=models.PROTECT, blank=True, null=True) @@ -36,6 +40,8 @@ class Port(models.Model): unique_together = ('switch', 'port') def clean(self): + if self.port > self.switch.number: + raise ValidationError("Ce port ne peut exister, numero trop élevé") if self.room and self.machine_interface or self.room and self.related or self.machine_interface and self.related: raise ValidationError("Chambre, interface et related_port sont mutuellement exclusifs") if self.related==self: @@ -52,6 +58,8 @@ class Port(models.Model): return str(self.switch) + " - " + str(self.port) class Room(models.Model): + PRETTY_NAME = "Chambre/ Prise murale" + name = models.CharField(max_length=255, unique=True) details = models.CharField(max_length=255, blank=True) diff --git a/users/models.py b/users/models.py index ea06fd37..d61c2091 100644 --- a/users/models.py +++ b/users/models.py @@ -101,6 +101,7 @@ class UserManager(BaseUserManager): class User(AbstractBaseUser): + PRETTY_NAME = "Utilisateurs" STATE_ACTIVE = 0 STATE_DISABLED = 1 STATE_ARCHIVE = 2 @@ -287,6 +288,7 @@ def user_post_delete(sender, **kwargs): #user.ldap_del() class ServiceUser(AbstractBaseUser): + PRETTY_NAME = "Utilisateurs de service" pseudo = models.CharField(max_length=32, unique=True, help_text="Doit contenir uniquement des lettres, chiffres, ou tirets", validators=[linux_user_validator]) @@ -323,6 +325,8 @@ def service_user_post_delete(sender, **kwargs): service_user.ldap_del() class Right(models.Model): + PRETTY_NAME = "Droits affectés à des users" + user = models.ForeignKey('User', on_delete=models.PROTECT) right = models.ForeignKey('ListRight', on_delete=models.PROTECT) @@ -343,6 +347,8 @@ def right_post_delete(sender, **kwargs): right.ldap_sync() class School(models.Model): + PRETTY_NAME = "Etablissements enregistrés" + name = models.CharField(max_length=255) def __str__(self): @@ -350,6 +356,8 @@ class School(models.Model): class ListRight(models.Model): + PRETTY_NAME = "Liste des droits existants" + listright = models.CharField(max_length=255, unique=True) gid = models.IntegerField(unique=True, null=True) @@ -383,12 +391,16 @@ def listright_post_delete(sender, **kwargs): right.ldap_del() class ListShell(models.Model): + PRETTY_NAME = "Liste des shells disponibles" + shell = models.CharField(max_length=255, unique=True) def __str__(self): return self.shell class Ban(models.Model): + PRETTY_NAME = "Liste des bannissements" + user = models.ForeignKey('User', on_delete=models.PROTECT) raison = models.CharField(max_length=255) date_start = models.DateTimeField(auto_now_add=True) @@ -399,6 +411,8 @@ class Ban(models.Model): class Whitelist(models.Model): + PRETTY_NAME = "Liste des accès gracieux" + user = models.ForeignKey('User', on_delete=models.PROTECT) raison = models.CharField(max_length=255) date_start = models.DateTimeField(auto_now_add=True)