8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-26 14:42:25 +00:00

Gestion de l'historique de tous les objets

This commit is contained in:
Gabriel Detraz 2016-07-21 16:58:12 +02:00
parent f42ed988cb
commit 79c4bdc1c1
25 changed files with 343 additions and 71 deletions

View file

@ -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)

View file

@ -14,7 +14,8 @@
<td>{{ article.prix }}</td>
<td>{{ article.cotisation }}</td>
<td>{{ article.duration }}</td>
<td>{% if is_trez %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-article' article.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}</td>
<td>{% if is_trez %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-article' article.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}
<a class="btn btn-info btn-sm" role="button" href="{% url 'cotisations:history' 'article' article.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -8,7 +8,8 @@
{% for banque in banque_list %}
<tr>
<td>{{ banque.name }}</td>
<td>{% if is_trez %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-banque' banque.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}</td>
<td>{% if is_trez %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-banque' banque.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}
<a class="btn btn-info btn-sm" role="button" href="{% url 'cotisations:history' 'banque' banque.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -8,6 +8,7 @@
<th>Date</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
{% for facture in facture_list %}
@ -17,9 +18,23 @@
<td>{{ facture.prix_total }}</td>
<td>{{ facture.paiement }}</td>
<td>{{ facture.date }}</td>
<td>{% if is_cableur %}{% if facture.valid and not facture.control or is_trez %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-facture' facture.id %}"><i class="glyphicon glyphicon-bitcoin"></i> Editer</a>{% endif %}{% endif %}</td>
<td>{% if is_cableur %}{% if facture.valid and not facture.control or is_trez %}<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-facture' facture.id %}"><i class="glyphicon glyphicon-trash"></i> Supprimer</a>{% else %}Facture controlée{% endif %}{% endif %}</td>
{% if is_cableur %}
<td><div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="editionfacture" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Modifier
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="editionfacture">
{% if facture.valid and not facture.control or is_trez %}
<li><a href="{% url 'cotisations:edit-facture' facture.id %}"><i class="glyphicon glyphicon-bitcoin"></i> Editer</a></li>
<li><a href="{% url 'cotisations:del-facture' facture.id %}"><i class="glyphicon glyphicon-trash"></i> Supprimer</a></li>
{% else %}
<li>Facture controlée</li>
{% endif %}
</ul></div></td>
{% endif %}
<td>{% if facture.valid %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:facture-pdf' facture.id %}"><i class="glyphicon glyphicon-save"></i> PDF</a>{% else %}Facture invalide{% endif %}</td>
<td><a class="btn btn-info btn-sm" role="button" href="{% url 'cotisations:history' 'facture' facture.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -8,7 +8,8 @@
{% for paiement in paiement_list %}
<tr>
<td>{{ paiement.moyen }}</td>
<td>{% if is_trez %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-paiement' paiement.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}</td>
<td>{% if is_trez %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-paiement' paiement.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}
<a class="btn btn-info btn-sm" role="button" href="{% url 'cotisations:history' 'paiement' paiement.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -7,7 +7,7 @@
<h2>Liste des banques</h2>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-banque' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter une banque</a>
{% if is_trez %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:del-banque' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer une ou plusieurs banques</a>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-banque' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer une ou plusieurs banques</a>
{% endif %}
{% include "cotisations/aff_banque.html" with banque_list=banque_list %}
<br />

View file

@ -7,7 +7,7 @@
<h2>Liste des types de paiements</h2>
{% if is_trez %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-paiement' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter un type de paiement</a>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:del-paiement' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer un ou plusieurs types de paiements</a>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-paiement' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer un ou plusieurs types de paiements</a>
{% endif %}
{% include "cotisations/aff_paiement.html" with paiement_list=paiement_list %}
<br />

View file

@ -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/(?P<object>facture)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>article)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>paiement)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>banque)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^control/$', views.control, name='control'),
url(r'^$', views.index, name='index'),
]

View file

@ -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})

View file

@ -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)

View file

@ -3,12 +3,14 @@
<tr>
<th>Extension</th>
<th></th>
<th></th>
</tr>
</thead>
{% for extension in extension_list %}
<tr>
<td>{{ extension.name }}</td>
<td>{% if is_infra %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:edit-extension' extension.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}</td>
<td><a class="btn btn-info btn-sm" role="button" href="{% url 'machines:history' 'extension' extension.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -9,7 +9,8 @@
<tr>
<td><p>{{ machine.user }}</p>
<p><a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:new-interface' machine.id %}"><i class="glyphicon glyphicon-plus"></i> Ajouter une interface</p></a>
<p><a class="btn btn-danger btn-sm" role="button" href="{% url 'machines:del-machine' machine.id %}"><i class="glyphicon glyphicon-trash"></i> Supprimer la machine</a></p></td>
<p><a class="btn btn-danger btn-sm" role="button" href="{% url 'machines:del-machine' machine.id %}"><i class="glyphicon glyphicon-trash"></i> Supprimer la machine</a></p>
<p><a class="btn btn-info btn-sm" role="button" href="{% url 'machines:history' 'machine' machine.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></p></td>
<td><table class="table table-striped">
<thead>
<tr>
@ -33,6 +34,7 @@
</button>
<ul class="dropdown-menu" aria-labelledby="editioninterface">
<li><a href="{% url 'machines:edit-interface' interface.id %}"><i class="glyphicon glyphicon-hdd"></i> Editer</a></li>
<li><a href="{% url 'machines:history' 'interface' interface.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></li>
<li><a href="{% url 'machines:del-interface' interface.id %}"><i class="glyphicon glyphicon-trash"></i> Supprimer</a></li>
</ul></div></td>
</tr>

View file

@ -4,6 +4,7 @@
<th>Type de machine</th>
<th>Extension</th>
<th></th>
<th></th>
</tr>
</thead>
{% for type in machinetype_list %}
@ -11,6 +12,7 @@
<td>{{ type.type }}</td>
<td>{{ type.extension }}</td>
<td>{% if is_infra %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:edit-machinetype' type.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}</td>
<td><a class="btn btn-info btn-sm" role="button" href="{% url 'machines:history' 'machinetype' type.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -7,7 +7,7 @@
<h2>Liste des extensions</h2>
{% if is_infra %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:add-extension' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter une extension</a>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:del-extension' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer une ou plusieurs extensions</a>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'machines:del-extension' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer une ou plusieurs extensions</a>
{% endif %}
{% include "machines/aff_extension.html" with extension_list=extension_list %}
<br />

View file

@ -7,7 +7,7 @@
<h2>Liste des types de machines</h2>
{% if is_infra %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:add-machinetype' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter un type de machine</a>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:del-machinetype' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer un ou plusieurs types de machines</a>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'machines:del-machinetype' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer un ou plusieurs types de machines</a>
{% endif %}
{% include "machines/aff_machinetype.html" with machinetype_list=machinetype_list %}
<br />

View file

@ -16,6 +16,10 @@ urlpatterns = [
url(r'^edit_extension/(?P<extensionid>[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/(?P<object>machine)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>interface)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>machinetype)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>extension)/(?P<id>[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'),

View file

@ -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):

View file

@ -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

View file

@ -6,6 +6,7 @@
<th>Date de début</th>
<th>Date de fin</th>
<th></th>
<th></th>
</tr>
</thead>
{% for ban in ban_list %}
@ -15,6 +16,7 @@
<td>{{ ban.date_start }}</td>
<td>{{ ban.date_end }}</td>
<td>{% if is_bofh %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-ban' ban.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a>{% endif %}</td>
<td><a class="btn btn-info btn-sm" role="button" href="{% url 'users:history' 'ban' ban.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -3,12 +3,14 @@
<tr>
<th>Etablissement</th>
<th></th>
<th></th>
</tr>
</thead>
{% for school in school_list %}
<tr>
<td>{{ school.name }}</td>
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-school' school.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a></td>
<td><a class="btn btn-info btn-sm" role="button" href="{% url 'users:history' 'school' school.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -6,6 +6,7 @@
<th>Date de début</th>
<th>Date de fin</th>
<th></th>
<th></th>
</tr>
</thead>
{% for whitelist in white_list %}
@ -15,6 +16,7 @@
<td>{{ whitelist.date_start }}</td>
<td>{{ whitelist.date_end }}</td>
<td>{% if is_cableur %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-whitelist' whitelist.id %}"><i class="glyphicon glyphicon-flag"></i> Editer</a>{% endif %}</td>
<td><a class="btn btn-info btn-sm" role="button" href="{% url 'users:history' 'whitelist' whitelist.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a></td>
</tr>
{% endfor %}
</table>

View file

@ -6,7 +6,7 @@
{% block content %}
<h2>Liste des Établissements</h2>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-school' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter un établissement</a>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:del-school' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer un ou plusieurs établissements</a>
<a class="btn btn-danger btn-sm" role="button" href="{% url 'users:del-school' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer un ou plusieurs établissements</a>
{% include "users/aff_schools.html" with school_list=school_list %}
<br />
<br />

View file

@ -9,6 +9,7 @@
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:password' user.id %}"><i class="glyphicon glyphicon-lock"></i> Changer le mot de passe</a>
{% if is_bureau %}<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:state' user.id %}"><i class="glyphicon glyphicon-flash"></i> Changer le statut</a>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-right' user.id %}"><i class="glyphicon glyphicon-ok"></i> Ajouter un droit</a>{% endif %}
<a class="btn btn-info btn-sm" role="button" href="{% url 'users:history' 'user' user.id %}"><i class="glyphicon glyphicon-repeat"></i> Historique</a>
<br />
<br />
<table class="table table-striped">

View file

@ -23,6 +23,10 @@ urlpatterns = [
url(r'^mon_profil/$', views.mon_profil, name='mon-profil'),
url(r'^process/(?P<token>[a-z0-9]{32})/$', views.process, name='process'),
url(r'^reset_password/$', views.reset_password, name='reset-password'),
url(r'^history/(?P<object>user)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>ban)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>whitelist)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^history/(?P<object>school)/(?P<id>[0-9]+)$', views.history, name='history'),
url(r'^$', views.index, name='index'),
]

View file

@ -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))