diff --git a/cotisations/admin.py b/cotisations/admin.py index 8a17c89a..6ef755b4 100644 --- a/cotisations/admin.py +++ b/cotisations/admin.py @@ -1,26 +1,24 @@ from django.contrib import admin +from reversion.admin import VersionAdmin from .models import Facture, Article, Banque, Paiement, Cotisation, Vente -class FactureAdmin(admin.ModelAdmin): +class FactureAdmin(VersionAdmin): list_display = ('user','paiement','date','valid','control') -class VenteAdmin(admin.ModelAdmin): +class VenteAdmin(VersionAdmin): list_display = ('facture','name','prix','number','iscotisation','duration') -class ArticleAdmin(admin.ModelAdmin): +class ArticleAdmin(VersionAdmin): list_display = ('name','prix','iscotisation','duration') -class BanqueAdmin(admin.ModelAdmin): +class BanqueAdmin(VersionAdmin): list_display = ('name',) -class PaiementAdmin(admin.ModelAdmin): +class PaiementAdmin(VersionAdmin): list_display = ('moyen',) -class PaiementAdmin(admin.ModelAdmin): - list_display = ('moyen',) - -class CotisationAdmin(admin.ModelAdmin): +class CotisationAdmin(VersionAdmin): list_display = ('vente','date_start','date_end') admin.site.register(Facture, FactureAdmin) diff --git a/cotisations/templates/cotisations/aff_article.html b/cotisations/templates/cotisations/aff_article.html index c14dbae2..c238ba13 100644 --- a/cotisations/templates/cotisations/aff_article.html +++ b/cotisations/templates/cotisations/aff_article.html @@ -14,7 +14,8 @@ {{ article.prix }} {{ article.cotisation }} {{ article.duration }} - {% if is_trez %} Editer{% endif %} + {% if is_trez %} Editer{% endif %} + Historique {% endfor %} diff --git a/cotisations/templates/cotisations/aff_banque.html b/cotisations/templates/cotisations/aff_banque.html index 9fb0736d..5e2c0eee 100644 --- a/cotisations/templates/cotisations/aff_banque.html +++ b/cotisations/templates/cotisations/aff_banque.html @@ -8,7 +8,8 @@ {% for banque in banque_list %} {{ banque.name }} - {% if is_trez %} Editer{% endif %} + {% if is_trez %} Editer{% endif %} + Historique {% endfor %} diff --git a/cotisations/templates/cotisations/aff_cotisations.html b/cotisations/templates/cotisations/aff_cotisations.html index 0d387ebb..18ed3865 100644 --- a/cotisations/templates/cotisations/aff_cotisations.html +++ b/cotisations/templates/cotisations/aff_cotisations.html @@ -8,6 +8,7 @@ Date + {% for facture in facture_list %} @@ -17,9 +18,23 @@ {{ facture.prix_total }} {{ facture.paiement }} {{ facture.date }} - {% if is_cableur %}{% if facture.valid and not facture.control or is_trez %} Editer{% endif %}{% endif %} - {% if is_cableur %}{% if facture.valid and not facture.control or is_trez %} Supprimer{% else %}Facture controlée{% endif %}{% endif %} + {% if is_cableur %} + + {% endif %} {% if facture.valid %} PDF{% else %}Facture invalide{% endif %} + Historique {% endfor %} diff --git a/cotisations/templates/cotisations/aff_paiement.html b/cotisations/templates/cotisations/aff_paiement.html index a2b8f11f..c6d838b7 100644 --- a/cotisations/templates/cotisations/aff_paiement.html +++ b/cotisations/templates/cotisations/aff_paiement.html @@ -8,7 +8,8 @@ {% for paiement in paiement_list %} {{ paiement.moyen }} - {% if is_trez %} Editer{% endif %} + {% if is_trez %} Editer{% endif %} + Historique {% endfor %} diff --git a/cotisations/templates/cotisations/index_banque.html b/cotisations/templates/cotisations/index_banque.html index 12802ad4..24dfba7c 100644 --- a/cotisations/templates/cotisations/index_banque.html +++ b/cotisations/templates/cotisations/index_banque.html @@ -7,7 +7,7 @@

Liste des banques

Ajouter une banque {% if is_trez %} - Supprimer une ou plusieurs banques + Supprimer une ou plusieurs banques {% endif %} {% include "cotisations/aff_banque.html" with banque_list=banque_list %}
diff --git a/cotisations/templates/cotisations/index_paiement.html b/cotisations/templates/cotisations/index_paiement.html index bc6204cd..72056c84 100644 --- a/cotisations/templates/cotisations/index_paiement.html +++ b/cotisations/templates/cotisations/index_paiement.html @@ -7,7 +7,7 @@

Liste des types de paiements

{% if is_trez %} Ajouter un type de paiement - Supprimer un ou plusieurs types de paiements + Supprimer un ou plusieurs types de paiements {% endif %} {% include "cotisations/aff_paiement.html" with paiement_list=paiement_list %}
diff --git a/cotisations/urls.py b/cotisations/urls.py index 4b320bb0..8e7fcc38 100644 --- a/cotisations/urls.py +++ b/cotisations/urls.py @@ -20,6 +20,10 @@ urlpatterns = [ url(r'^index_article/$', views.index_article, name='index-article'), url(r'^index_banque/$', views.index_banque, name='index-banque'), url(r'^index_paiement/$', views.index_paiement, name='index-paiement'), + url(r'^history/(?Pfacture)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Particle)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Ppaiement)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Pbanque)/(?P[0-9]+)$', views.history, name='history'), url(r'^control/$', views.control, name='control'), url(r'^$', views.index, name='index'), ] diff --git a/cotisations/views.py b/cotisations/views.py index 08684ac5..55bed964 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -8,8 +8,10 @@ from django.template import Context, RequestContext, loader from django.contrib.auth.decorators import login_required, permission_required from django.contrib import messages from django.db.models import Max, ProtectedError +from django.db import transaction from django.forms import modelformset_factory, formset_factory import os +from reversion import revisions as reversion from .models import Facture, Article, Vente, Cotisation, Paiement, Banque from .forms import NewFactureForm, TrezEditFactureForm, EditFactureForm, ArticleForm, DelArticleForm, PaiementForm, DelPaiementForm, BanqueForm, DelBanqueForm, NewFactureFormPdf, SelectArticleForm @@ -56,13 +58,19 @@ def new_facture(request, userid): articles = article_formset # Si au moins un article est rempli if any(art.cleaned_data for art in articles): - new_facture.save() + with transaction.atomic(), reversion.create_revision(): + new_facture.save() + reversion.set_user(request.user) + reversion.set_comment("Création") for art_item in articles: if art_item.cleaned_data: article = art_item.cleaned_data['article'] quantity = art_item.cleaned_data['quantity'] new_vente = Vente.objects.create(facture=new_facture, name=article.name, prix=article.prix, iscotisation=article.iscotisation, duration=article.duration, number=quantity) - new_vente.save() + with transaction.atomic(), reversion.create_revision(): + new_vente.save() + reversion.set_user(request.user) + reversion.set_comment("Création") if art_item.cleaned_data['article'].iscotisation: create_cotis(new_vente, user, art_item.cleaned_data['article'].duration*art_item.cleaned_data['quantity']) if any(art_item.cleaned_data['article'].iscotisation for art_item in articles if art_item.cleaned_data): @@ -130,8 +138,11 @@ def edit_facture(request, factureid): vente_form_set = modelformset_factory(Vente, fields=('name','number'), extra=0, max_num=len(ventes_objects)) vente_form = vente_form_set(request.POST or None, queryset=ventes_objects) if facture_form.is_valid() and vente_form.is_valid(): - facture_form.save() - vente_form.save() + with transaction.atomic(), reversion.create_revision(): + facture_form.save() + vente_form.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for form in vente_form for field in facture_form.changed_data + form.changed_data)) messages.success(request, "La facture a bien été modifiée") return redirect("/cotisations/") return form({'factureform': facture_form, 'venteform': vente_form}, 'cotisations/edit_facture.html', request) @@ -148,7 +159,9 @@ def del_facture(request, factureid): messages.error(request, "Vous ne pouvez pas editer une facture controlée ou invalidée par le trésorier") return redirect("/cotisations/") if request.method == "POST": - facture.delete() + with transaction.atomic(), reversion.create_revision(): + facture.delete() + reversion.set_user(request.user) messages.success(request, "La facture a été détruite") return redirect("/cotisations/") return form({'objet': facture, 'objet_name': 'facture'}, 'cotisations/delete.html', request) @@ -158,7 +171,10 @@ def del_facture(request, factureid): def add_article(request): article = ArticleForm(request.POST or None) if article.is_valid(): - article.save() + with transaction.atomic(), reversion.create_revision(): + article.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "L'article a été ajouté") return redirect("/cotisations/index_article/") return form({'factureform': article}, 'cotisations/facture.html', request) @@ -173,7 +189,10 @@ def edit_article(request, articleid): return redirect("/cotisations/index_article/") article = ArticleForm(request.POST or None, instance=article_instance) if article.is_valid(): - article.save() + with transaction.atomic(), reversion.create_revision(): + article.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in article.changed_data)) messages.success(request, "Type d'article modifié") return redirect("/cotisations/index_article/") return form({'factureform': article}, 'cotisations/facture.html', request) @@ -184,7 +203,9 @@ def del_article(request): article = DelArticleForm(request.POST or None) if article.is_valid(): article_del = article.cleaned_data['articles'] - article_del.delete() + with transaction.atomic(), reversion.create_revision(): + article_del.delete() + reversion.set_user(request.user) messages.success(request, "Le/les articles ont été supprimé") return redirect("/cotisations/index_article") return form({'factureform': article}, 'cotisations/facture.html', request) @@ -194,7 +215,10 @@ def del_article(request): def add_paiement(request): paiement = PaiementForm(request.POST or None) if paiement.is_valid(): - paiement.save() + with transaction.atomic(), reversion.create_revision(): + paiement.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "Le moyen de paiement a été ajouté") return redirect("/cotisations/index_paiement/") return form({'factureform': paiement}, 'cotisations/facture.html', request) @@ -209,7 +233,10 @@ def edit_paiement(request, paiementid): return redirect("/cotisations/index_paiement/") paiement = PaiementForm(request.POST or None, instance=paiement_instance) if paiement.is_valid(): - paiement.save() + with transaction.atomic(), reversion.create_revision(): + paiement.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in paiement.changed_data)) messages.success(request, "Type de paiement modifié") return redirect("/cotisations/index_paiement/") return form({'factureform': paiement}, 'cotisations/facture.html', request) @@ -222,7 +249,10 @@ def del_paiement(request): paiement_dels = paiement.cleaned_data['paiements'] for paiement_del in paiement_dels: try: - paiement_del.delete() + with transaction.atomic(), reversion.create_revision(): + paiement_del.delete() + reversion.set_user(request.user) + reversion.set_comment("Destruction") messages.success(request, "Le moyen de paiement a été supprimé") except ProtectedError: messages.error(request, "Le moyen de paiement %s est affecté à au moins une facture, vous ne pouvez pas le supprimer" % paiement_del) @@ -234,7 +264,10 @@ def del_paiement(request): def add_banque(request): banque = BanqueForm(request.POST or None) if banque.is_valid(): - banque.save() + with transaction.atomic(), reversion.create_revision(): + banque.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "La banque a été ajoutée") return redirect("/cotisations/index_banque/") return form({'factureform': banque}, 'cotisations/facture.html', request) @@ -249,7 +282,10 @@ def edit_banque(request, banqueid): return redirect("/cotisations/index_banque/") banque = BanqueForm(request.POST or None, instance=banque_instance) if banque.is_valid(): - banque.save() + with transaction.atomic(), reversion.create_revision(): + banque.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in banque.changed_data)) messages.success(request, "Banque modifiée") return redirect("/cotisations/index_banque/") return form({'factureform': banque}, 'cotisations/facture.html', request) @@ -262,7 +298,10 @@ def del_banque(request): banque_dels = banque.cleaned_data['banques'] for banque_del in banque_dels: try: - banque_del.delete() + with transaction.atomic(), reversion.create_revision(): + banque_del.delete() + reversion.set_user(request.user) + reversion.set_comment("Destruction") messages.success(request, "La banque a été supprimée") except ProtectedError: messages.error(request, "La banque %s est affectée à au moins une facture, vous ne pouvez pas la supprimer" % banque_del) @@ -303,3 +342,38 @@ def index_banque(request): def index(request): facture_list = Facture.objects.order_by('date').reverse() return render(request, 'cotisations/index.html', {'facture_list': facture_list}) + +@login_required +def history(request, object, id): + if object == 'facture': + try: + object_instance = Facture.objects.get(pk=id) + except Facture.DoesNotExist: + messages.error(request, "Facture inexistante") + return redirect("/cotisations/") + if not request.user.has_perms(('cableur',)) and object_instance.user != request.user: + messages.error(request, "Vous ne pouvez pas afficher l'historique d'une facture d'un autre user que vous sans droit cableur") + return redirect("/users/profil/" + str(request.user.id)) + elif object == 'paiement' and request.user.has_perms(('cableur',)): + try: + object_instance = Paiement.objects.get(pk=id) + except Paiement.DoesNotExist: + messages.error(request, "Paiement inexistant") + return redirect("/cotisations/") + elif object == 'article' and request.user.has_perms(('cableur',)): + try: + object_instance = Article.objects.get(pk=id) + except Article.DoesNotExist: + messages.error(request, "Article inexistante") + return redirect("/cotisations/") + elif object == 'banque' and request.user.has_perms(('cableur',)): + try: + object_instance = Banque.objects.get(pk=id) + except Banque.DoesNotExist: + messages.error(request, "Banque inexistante") + return redirect("/cotisations/") + else: + messages.error(request, "Objet inconnu") + return redirect("/cotisations/") + reversions = reversion.get_for_object(object_instance) + return render(request, 're2o/history.html', {'reversions': reversions, 'object': object_instance}) diff --git a/machines/admin.py b/machines/admin.py index 850e8a9b..b4446277 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -1,20 +1,21 @@ from django.contrib import admin +from reversion.admin import VersionAdmin from .models import Machine, MachineType, IpList, Interface, Extension -class MachineAdmin(admin.ModelAdmin): +class MachineAdmin(VersionAdmin): list_display = ('user','name','active') -class MachineTypeAdmin(admin.ModelAdmin): +class MachineTypeAdmin(VersionAdmin): list_display = ('type','extension') -class ExtensionAdmin(admin.ModelAdmin): +class ExtensionAdmin(VersionAdmin): list_display = ('name',) -class IpListAdmin(admin.ModelAdmin): +class IpListAdmin(VersionAdmin): list_display = ('ipv4',) -class InterfaceAdmin(admin.ModelAdmin): +class InterfaceAdmin(VersionAdmin): list_display = ('machine','type','dns','mac_address','ipv4','details') admin.site.register(Machine, MachineAdmin) diff --git a/machines/templates/machines/aff_extension.html b/machines/templates/machines/aff_extension.html index 85f57f65..f1ab63d5 100644 --- a/machines/templates/machines/aff_extension.html +++ b/machines/templates/machines/aff_extension.html @@ -3,12 +3,14 @@ Extension + {% for extension in extension_list %} {{ extension.name }} {% if is_infra %} Editer{% endif %} + Historique {% endfor %} diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html index 40690a59..ccb27844 100644 --- a/machines/templates/machines/aff_machines.html +++ b/machines/templates/machines/aff_machines.html @@ -9,7 +9,8 @@

{{ machine.user }}

Ajouter une interface

-

Supprimer la machine

+

Supprimer la machine

+

Historique

@@ -33,6 +34,7 @@ diff --git a/machines/templates/machines/aff_machinetype.html b/machines/templates/machines/aff_machinetype.html index 7a7832d0..255c94ee 100644 --- a/machines/templates/machines/aff_machinetype.html +++ b/machines/templates/machines/aff_machinetype.html @@ -4,6 +4,7 @@ + {% for type in machinetype_list %} @@ -11,6 +12,7 @@ + {% endfor %}
Type de machine Extension
{{ type.type }} {{ type.extension }} {% if is_infra %} Editer{% endif %} Historique
diff --git a/machines/templates/machines/index_extension.html b/machines/templates/machines/index_extension.html index 35c13f00..e27e59b6 100644 --- a/machines/templates/machines/index_extension.html +++ b/machines/templates/machines/index_extension.html @@ -7,7 +7,7 @@

Liste des extensions

{% if is_infra %} Ajouter une extension - Supprimer une ou plusieurs extensions + Supprimer une ou plusieurs extensions {% endif %} {% include "machines/aff_extension.html" with extension_list=extension_list %}
diff --git a/machines/templates/machines/index_machinetype.html b/machines/templates/machines/index_machinetype.html index bc38795e..082e9e09 100644 --- a/machines/templates/machines/index_machinetype.html +++ b/machines/templates/machines/index_machinetype.html @@ -7,7 +7,7 @@

Liste des types de machines

{% if is_infra %} Ajouter un type de machine - Supprimer un ou plusieurs types de machines + Supprimer un ou plusieurs types de machines {% endif %} {% include "machines/aff_machinetype.html" with machinetype_list=machinetype_list %}
diff --git a/machines/urls.py b/machines/urls.py index 3205ddb9..6327d2cc 100644 --- a/machines/urls.py +++ b/machines/urls.py @@ -16,6 +16,10 @@ urlpatterns = [ url(r'^edit_extension/(?P[0-9]+)$', views.edit_extension, name='edit-extension'), url(r'^del_extension/$', views.del_extension, name='del-extension'), url(r'^index_extension/$', views.index_extension, name='index-extension'), + url(r'^history/(?Pmachine)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Pinterface)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Pmachinetype)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Pextension)/(?P[0-9]+)$', views.history, name='history'), url(r'^$', views.index, name='index'), url(r'^rest/mac-ip/$', views.mac_ip, name='mac-ip'), url(r'^rest/dns-ip/$', views.dns_ip, name='dns-ip'), diff --git a/machines/views.py b/machines/views.py index 1774a6a2..327e2483 100644 --- a/machines/views.py +++ b/machines/views.py @@ -10,9 +10,11 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required from django.db.models import ProtectedError from django.forms import ValidationError +from django.db import transaction from rest_framework.renderers import JSONRenderer from machines.serializers import InterfaceSerializer +from reversion import revisions as reversion import re @@ -52,7 +54,9 @@ def assign_ips(user): for machine in machines: if not machine.ipv4: interface = assign_ipv4(machine) - interface.save() + with transaction.atomic(), reversion.create_revision(): + reversion.set_comment("Assignation ipv4") + interface.save() return def free_ip(): @@ -68,7 +72,9 @@ def assign_ipv4(interface): def unassign_ipv4(interface): interface.ipv4 = None - interface.save() + with transaction.atomic(), reversion.create_revision(): + reversion.set_comment("Désassignation ipv4") + interface.save() def form(ctx, template, request): c = ctx @@ -92,13 +98,19 @@ def new_machine(request, userid): new_machine.user = user new_interface = interface.save(commit=False) if full_domain_validator(request, new_interface): - new_machine.save() + with transaction.atomic(), reversion.create_revision(): + new_machine.save() + reversion.set_user(request.user) + reversion.set_comment("Création") new_interface.machine = new_machine if free_ip() and not new_interface.ipv4: new_interface = assign_ipv4(new_interface) elif not new_interface.ipv4: messages.error(request, u"Il n'y a plus d'ip disponibles") - new_interface.save() + with transaction.atomic(), reversion.create_revision(): + new_interface.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "La machine a été crée") return redirect("/users/profil/" + userid) return form({'machineform': machine, 'interfaceform': interface}, 'machines/machine.html', request) @@ -123,8 +135,14 @@ def edit_interface(request, interfaceid): new_interface = interface_form.save(commit=False) new_machine = machine_form.save(commit=False) if full_domain_validator(request, new_interface): - new_machine.save() - new_interface.save() + with transaction.atomic(), reversion.create_revision(): + new_machine.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in machine_form.changed_data)) + with transaction.atomic(), reversion.create_revision(): + new_interface.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in interface_form.changed_data)) messages.success(request, "La machine a été modifiée") return redirect("/users/profil/" + str(interface.machine.user.id)) return form({'machineform': machine_form, 'interfaceform': interface_form}, 'machines/machine.html', request) @@ -141,7 +159,9 @@ def del_machine(request, machineid): messages.error(request, "Vous ne pouvez pas éditer une machine d'un autre user que vous sans droit") return redirect("/users/profil/" + str(request.user.id)) if request.method == "POST": - machine.delete() + with transaction.atomic(), reversion.create_revision(): + machine.delete() + reversion.set_user(request.user) messages.success(request, "La machine a été détruite") return redirect("/users/profil/" + str(request.user.id)) return form({'objet': machine, 'objet_name': 'machine'}, 'machines/delete.html', request) @@ -166,7 +186,10 @@ def new_interface(request, machineid): new_interface = assign_ipv4(new_interface) elif not new_interface.ipv4: messages.error(request, u"Il n'y a plus d'ip disponibles") - new_interface.save() + with transaction.atomic(), reversion.create_revision(): + new_interface.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "L'interface a été ajoutée") return redirect("/users/profil/" + str(request.user.id)) return form({'interfaceform': interface_form}, 'machines/machine.html', request) @@ -183,7 +206,9 @@ def del_interface(request, interfaceid): messages.error(request, "Vous ne pouvez pas éditer une machine d'un autre user que vous sans droit") return redirect("/users/profil/" + str(request.user.id)) if request.method == "POST": - interface.delete() + with transaction.atomic(), reversion.create_revision(): + interface.delete() + reversion.set_user(request.user) messages.success(request, "L'interface a été détruite") return redirect("/users/profil/" + str(request.user.id)) return form({'objet': interface, 'objet_name': 'interface'}, 'machines/delete.html', request) @@ -193,7 +218,10 @@ def del_interface(request, interfaceid): def add_machinetype(request): machinetype = MachineTypeForm(request.POST or None) if machinetype.is_valid(): - machinetype.save() + with transaction.atomic(), reversion.create_revision(): + machinetype.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "Ce type de machine a été ajouté") return redirect("/machines/index_machinetype") return form({'machineform': machinetype, 'interfaceform': None}, 'machines/machine.html', request) @@ -208,7 +236,10 @@ def edit_machinetype(request, machinetypeid): return redirect("/machines/index_machinetype/") machinetype = MachineTypeForm(request.POST or None, instance=machinetype_instance) if machinetype.is_valid(): - machinetype.save() + with transaction.atomic(), reversion.create_revision(): + machinetype.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in machinetype.changed_data)) messages.success(request, "Type de machine modifié") return redirect("/machines/index_machinetype/") return form({'machineform': machinetype}, 'machines/machine.html', request) @@ -221,7 +252,9 @@ def del_machinetype(request): machinetype_dels = machinetype.cleaned_data['machinetypes'] for machinetype_del in machinetype_dels: try: - machinetype_del.delete() + with transaction.atomic(), reversion.create_revision(): + machinetype_del.delete() + reversion.set_user(request.user) messages.success(request, "Le type de machine a été supprimé") except ProtectedError: messages.error(request, "Le type de machine %s est affectée à au moins une machine, vous ne pouvez pas le supprimer" % machinetype_del) @@ -233,7 +266,10 @@ def del_machinetype(request): def add_extension(request): extension = ExtensionForm(request.POST or None) if extension.is_valid(): - extension.save() + with transaction.atomic(), reversion.create_revision(): + extension.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "Cette extension a été ajoutée") return redirect("/machines/index_extension") return form({'machineform': extension, 'interfaceform': None}, 'machines/machine.html', request) @@ -248,7 +284,10 @@ def edit_extension(request, extensionid): return redirect("/machines/index_extension/") extension = ExtensionForm(request.POST or None, instance=extension_instance) if extension.is_valid(): - extension.save() + with transaction.atomic(), reversion.create_revision(): + extension.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in extension.changed_data)) messages.success(request, "Extension modifiée") return redirect("/machines/index_extension/") return form({'machineform': extension}, 'machines/machine.html', request) @@ -261,7 +300,9 @@ def del_extension(request): extension_dels = extension.cleaned_data['extensions'] for extension_del in extension_dels: try: - extension_del.delete() + with transaction.atomic(), reversion.create_revision(): + extension_del.delete() + reversion.set_user(request.user) messages.success(request, "L'extension a été supprimée") except ProtectedError: messages.error(request, "L'extension %s est affectée à au moins un type de machine, vous ne pouvez pas la supprimer" % extension_del) @@ -286,6 +327,45 @@ def index_extension(request): extension_list = Extension.objects.order_by('name') return render(request, 'machines/index_extension.html', {'extension_list':extension_list}) +@login_required +def history(request, object, id): + if object == 'machine': + try: + object_instance = Machine.objects.get(pk=id) + except Machine.DoesNotExist: + messages.error(request, "Machine inexistante") + return redirect("/machines/") + if not request.user.has_perms(('cableur',)) and object_instance.user != request.user: + messages.error(request, "Vous ne pouvez pas afficher l'historique d'une machine d'un autre user que vous sans droit cableur") + return redirect("/users/profil/" + str(request.user.id)) + elif object == 'interface': + try: + object_instance = Interface.objects.get(pk=id) + except Interface.DoesNotExist: + messages.error(request, "Interface inexistante") + return redirect("/machines/") + if not request.user.has_perms(('cableur',)) and object_instance.machine.user != request.user: + messages.error(request, "Vous ne pouvez pas afficher l'historique d'une interface d'un autre user que vous sans droit cableur") + return redirect("/users/profil/" + str(request.user.id)) + elif object == 'machinetype' and request.user.has_perms(('cableur',)): + try: + object_instance = MachineType.objects.get(pk=id) + except MachineType.DoesNotExist: + messages.error(request, "Type de machine inexistant") + return redirect("/machines/") + elif object == 'extension' and request.user.has_perms(('cableur',)): + try: + object_instance = Extension.objects.get(pk=id) + except Extension.DoesNotExist: + messages.error(request, "Extension inexistante") + return redirect("/machines/") + else: + messages.error(request, "Objet inconnu") + return redirect("/machines/") + reversions = reversion.get_for_object(object_instance) + return render(request, 're2o/history.html', {'reversions': reversions, 'object': object_instance}) + + """ Framework Rest """ class JSONResponse(HttpResponse): diff --git a/users/admin.py b/users/admin.py index 884e7200..ecdea20e 100644 --- a/users/admin.py +++ b/users/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.contrib.auth.models import Group from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from reversion.admin import VersionAdmin from .models import User, School, Right, ListRight, Ban, Whitelist, Request from .forms import UserChangeForm, UserCreationForm @@ -18,11 +19,11 @@ class UserAdmin(admin.ModelAdmin): ) -class SchoolAdmin(admin.ModelAdmin): +class SchoolAdmin(VersionAdmin): list_display = ('name',) -class ListRightAdmin(admin.ModelAdmin): +class ListRightAdmin(VersionAdmin): list_display = ('listright',) @@ -32,15 +33,15 @@ class RightAdmin(admin.ModelAdmin): class RequestAdmin(admin.ModelAdmin): list_display = ('user', 'type', 'created_at', 'expires_at') -class BanAdmin(admin.ModelAdmin): +class BanAdmin(VersionAdmin): list_display = ('user', 'raison', 'date_start', 'date_end') -class WhitelistAdmin(admin.ModelAdmin): +class WhitelistAdmin(VersionAdmin): list_display = ('user', 'raison', 'date_start', 'date_end') -class UserAdmin(BaseUserAdmin): +class UserAdmin(VersionAdmin, BaseUserAdmin): # The forms to add and change user instances form = UserChangeForm add_form = UserCreationForm diff --git a/users/templates/users/aff_bans.html b/users/templates/users/aff_bans.html index e6a08c30..e4b410f9 100644 --- a/users/templates/users/aff_bans.html +++ b/users/templates/users/aff_bans.html @@ -6,6 +6,7 @@ Date de début Date de fin + {% for ban in ban_list %} @@ -15,6 +16,7 @@ {{ ban.date_start }} {{ ban.date_end }} {% if is_bofh %} Editer{% endif %} + Historique {% endfor %} diff --git a/users/templates/users/aff_schools.html b/users/templates/users/aff_schools.html index 0f9f73b5..4853f5d5 100644 --- a/users/templates/users/aff_schools.html +++ b/users/templates/users/aff_schools.html @@ -3,12 +3,14 @@ Etablissement + {% for school in school_list %} {{ school.name }} Editer + Historique {% endfor %} diff --git a/users/templates/users/aff_whitelists.html b/users/templates/users/aff_whitelists.html index 2c03c217..0aec79fa 100644 --- a/users/templates/users/aff_whitelists.html +++ b/users/templates/users/aff_whitelists.html @@ -6,6 +6,7 @@ Date de début Date de fin + {% for whitelist in white_list %} @@ -15,6 +16,7 @@ {{ whitelist.date_start }} {{ whitelist.date_end }} {% if is_cableur %} Editer{% endif %} + Historique {% endfor %} diff --git a/users/templates/users/index_schools.html b/users/templates/users/index_schools.html index eaf63414..008129db 100644 --- a/users/templates/users/index_schools.html +++ b/users/templates/users/index_schools.html @@ -6,7 +6,7 @@ {% block content %}

Liste des Établissements

Ajouter un établissement - Supprimer un ou plusieurs établissements + Supprimer un ou plusieurs établissements {% include "users/aff_schools.html" with school_list=school_list %}

diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index 9e2d95df..de0fede0 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -9,6 +9,7 @@ Changer le mot de passe {% if is_bureau %} Changer le statut Ajouter un droit{% endif %} + Historique

diff --git a/users/urls.py b/users/urls.py index 863db9dc..89dda33c 100644 --- a/users/urls.py +++ b/users/urls.py @@ -23,6 +23,10 @@ urlpatterns = [ url(r'^mon_profil/$', views.mon_profil, name='mon-profil'), url(r'^process/(?P[a-z0-9]{32})/$', views.process, name='process'), url(r'^reset_password/$', views.reset_password, name='reset-password'), + url(r'^history/(?Puser)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Pban)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Pwhitelist)/(?P[0-9]+)$', views.history, name='history'), + url(r'^history/(?Pschool)/(?P[0-9]+)$', views.history, name='history'), url(r'^$', views.index, name='index'), ] diff --git a/users/views.py b/users/views.py index 04637b75..66322fb5 100644 --- a/users/views.py +++ b/users/views.py @@ -11,7 +11,9 @@ from django.db import IntegrityError from django.core.mail import send_mail from django.utils import timezone from django.core.urlresolvers import reverse +from django.db import transaction +from reversion import revisions as reversion from users.models import User, Right, Ban, Whitelist, School, Request from users.models import DelRightForm, BanForm, WhitelistForm, DelSchoolForm from users.models import InfoForm, BaseInfoForm, StateForm, RightForm, SchoolForm @@ -50,7 +52,9 @@ def password_change_action(u_form, user, request, req=False): return form({'userform': u_form}, 'users/user.html', request) user.set_password(u_form.cleaned_data['passwd1']) user.pwd_ntlm = hashNT(u_form.cleaned_data['passwd1']) - user.save() + with transaction.atomic(), reversion.create_revision(): + user.save() + reversion.set_comment("Réinitialisation du mot de passe") messages.success(request, "Le mot de passe a changé") if req: req.delete() @@ -78,14 +82,17 @@ def new_user(request): user = InfoForm(request.POST or None) if user.is_valid(): user = user.save(commit=False) - user.save() + with transaction.atomic(), reversion.create_revision(): + user.save() + reversion.set_user(request.user) + reversion.set_comment("Création") req = Request() req.type = Request.PASSWD req.user = user req.save() reset_passwd_mail(req, request) messages.success(request, "L'utilisateur %s a été crée, un mail pour l'initialisation du mot de passe a été envoyé" % user.pseudo) - redirect("/users/profil/" + user.id) + return redirect("/users/profil/" + user.id) return form({'userform': user}, 'users/user.html', request) @login_required @@ -103,7 +110,10 @@ def edit_info(request, userid): else: user = InfoForm(request.POST or None, instance=user) if user.is_valid(): - user.save() + with transaction.atomic(), reversion.create_revision(): + user.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in user.changed_data)) messages.success(request, "L'user a bien été modifié") return redirect("/users/profil/" + userid) return form({'userform': user}, 'users/user.html', request) @@ -123,7 +133,10 @@ def state(request, userid): archive(user) else: unarchive(user) - state.save() + with transaction.atomic(), reversion.create_revision(): + state.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in state.changed_data)) messages.success(request, "Etat changé avec succès") return redirect("/users/profil/" + userid) return form({'userform': state}, 'users/user.html', request) @@ -188,7 +201,10 @@ def add_ban(request, userid): ban_instance = Ban(user=user) ban = BanForm(request.POST or None, instance=ban_instance) if ban.is_valid(): - ban.save() + with transaction.atomic(), reversion.create_revision(): + ban.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "Bannissement ajouté") return redirect("/users/profil/" + userid) if user.is_ban(): @@ -208,7 +224,10 @@ def edit_ban(request, banid): return redirect("/users/") ban = BanForm(request.POST or None, instance=ban_instance) if ban.is_valid(): - ban.save() + with transaction.atomic(), reversion.create_revision(): + ban.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in ban.changed_data)) messages.success(request, "Bannissement modifié") return redirect("/users/") return form({'userform': ban}, 'users/user.html', request) @@ -224,7 +243,10 @@ def add_whitelist(request, userid): whitelist_instance = Whitelist(user=user) whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance) if whitelist.is_valid(): - whitelist.save() + with transaction.atomic(), reversion.create_revision(): + whitelist.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "Accès à titre gracieux accordé") return redirect("/users/profil/" + userid) if is_whitelisted(user): @@ -244,7 +266,10 @@ def edit_whitelist(request, whitelistid): return redirect("/users/") whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance) if whitelist.is_valid(): - whitelist.save() + with transaction.atomic(), reversion.create_revision(): + whitelist.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in whitelist.changed_data)) messages.success(request, "Whitelist modifiée") return redirect("/users/") return form({'userform': whitelist}, 'users/user.html', request) @@ -254,7 +279,10 @@ def edit_whitelist(request, whitelistid): def add_school(request): school = SchoolForm(request.POST or None) if school.is_valid(): - school.save() + with transaction.atomic(), reversion.create_revision(): + school.save() + reversion.set_user(request.user) + reversion.set_comment("Création") messages.success(request, "L'établissement a été ajouté") return redirect("/users/index_school/") return form({'userform': school}, 'users/user.html', request) @@ -269,7 +297,10 @@ def edit_school(request, schoolid): return redirect("/users/") school = SchoolForm(request.POST or None, instance=school_instance) if school.is_valid(): - school.save() + with transaction.atomic(), reversion.create_revision(): + school.save() + reversion.set_user(request.user) + reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in school.changed_data)) messages.success(request, "Établissement modifié") return redirect("/users/index_school/") return form({'userform': school}, 'users/user.html', request) @@ -282,7 +313,9 @@ def del_school(request): school_dels = school.cleaned_data['schools'] for school_del in school_dels: try: - school_del.delete() + with transaction.atomic(), reversion.create_revision(): + school_del.delete() + reversion.set_comment("Destruction") messages.success(request, "L'établissement a été supprimé") except ProtectedError: messages.error( @@ -320,6 +353,48 @@ def index_school(request): school_list = School.objects.order_by('name') return render(request, 'users/index_schools.html', {'school_list':school_list}) +@login_required +def history(request, object, id): + if object == 'user': + try: + object_instance = User.objects.get(pk=id) + except User.DoesNotExist: + messages.error(request, "Utilisateur inexistant") + return redirect("/users/") + if not request.user.has_perms(('cableur',)) and object_instance != request.user: + messages.error(request, "Vous ne pouvez pas afficher l'historique d'un autre user que vous sans droit cableur") + return redirect("/users/profil/" + str(request.user.id)) + elif object == 'ban': + try: + object_instance = Ban.objects.get(pk=id) + except Ban.DoesNotExist: + messages.error(request, "Bannissement inexistant") + return redirect("/users/") + if not request.user.has_perms(('cableur',)) and object_instance.user != request.user: + messages.error(request, "Vous ne pouvez pas afficher les bans d'un autre user que vous sans droit cableur") + return redirect("/users/profil/" + str(request.user.id)) + elif object == 'whitelist': + try: + object_instance = Whitelist.objects.get(pk=id) + except Whiltelist.DoesNotExist: + messages.error(request, "Whitelist inexistant") + return redirect("/users/") + if not request.user.has_perms(('cableur',)) and object_instance.user != request.user: + messages.error(request, "Vous ne pouvez pas afficher les whitelist d'un autre user que vous sans droit cableur") + return redirect("/users/profil/" + str(request.user.id)) + elif object == 'school' and request.user.has_perms(('cableur',)): + try: + object_instance = School.objects.get(pk=id) + except School.DoesNotExist: + messages.error(request, "Ecole inexistante") + return redirect("/users/") + else: + messages.error(request, "Objet inconnu") + return redirect("/users/") + reversions = reversion.get_for_object(object_instance) + return render(request, 're2o/history.html', {'reversions': reversions, 'object': object_instance}) + + @login_required def mon_profil(request): return redirect("/users/profil/" + str(request.user.id))