8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-23 20:03:11 +00:00

Gestion de l'historique de tous les objets

This commit is contained in:
chirac 2016-07-21 16:58:12 +02:00
parent 7bd2e31842
commit 38a59b75bd
25 changed files with 343 additions and 71 deletions

View file

@ -1,26 +1,24 @@
from django.contrib import admin from django.contrib import admin
from reversion.admin import VersionAdmin
from .models import Facture, Article, Banque, Paiement, Cotisation, Vente from .models import Facture, Article, Banque, Paiement, Cotisation, Vente
class FactureAdmin(admin.ModelAdmin): class FactureAdmin(VersionAdmin):
list_display = ('user','paiement','date','valid','control') list_display = ('user','paiement','date','valid','control')
class VenteAdmin(admin.ModelAdmin): class VenteAdmin(VersionAdmin):
list_display = ('facture','name','prix','number','iscotisation','duration') list_display = ('facture','name','prix','number','iscotisation','duration')
class ArticleAdmin(admin.ModelAdmin): class ArticleAdmin(VersionAdmin):
list_display = ('name','prix','iscotisation','duration') list_display = ('name','prix','iscotisation','duration')
class BanqueAdmin(admin.ModelAdmin): class BanqueAdmin(VersionAdmin):
list_display = ('name',) list_display = ('name',)
class PaiementAdmin(admin.ModelAdmin): class PaiementAdmin(VersionAdmin):
list_display = ('moyen',) list_display = ('moyen',)
class PaiementAdmin(admin.ModelAdmin): class CotisationAdmin(VersionAdmin):
list_display = ('moyen',)
class CotisationAdmin(admin.ModelAdmin):
list_display = ('vente','date_start','date_end') list_display = ('vente','date_start','date_end')
admin.site.register(Facture, FactureAdmin) admin.site.register(Facture, FactureAdmin)

View file

@ -14,7 +14,8 @@
<td>{{ article.prix }}</td> <td>{{ article.prix }}</td>
<td>{{ article.cotisation }}</td> <td>{{ article.cotisation }}</td>
<td>{{ article.duration }}</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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -8,7 +8,8 @@
{% for banque in banque_list %} {% for banque in banque_list %}
<tr> <tr>
<td>{{ banque.name }}</td> <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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -8,6 +8,7 @@
<th>Date</th> <th>Date</th>
<th></th> <th></th>
<th></th> <th></th>
<th></th>
</tr> </tr>
</thead> </thead>
{% for facture in facture_list %} {% for facture in facture_list %}
@ -17,9 +18,23 @@
<td>{{ facture.prix_total }}</td> <td>{{ facture.prix_total }}</td>
<td>{{ facture.paiement }}</td> <td>{{ facture.paiement }}</td>
<td>{{ facture.date }}</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> {% if is_cableur %}
<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> <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>{% 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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -8,7 +8,8 @@
{% for paiement in paiement_list %} {% for paiement in paiement_list %}
<tr> <tr>
<td>{{ paiement.moyen }}</td> <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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -7,7 +7,7 @@
<h2>Liste des banques</h2> <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> <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 %} {% 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 %} {% endif %}
{% include "cotisations/aff_banque.html" with banque_list=banque_list %} {% include "cotisations/aff_banque.html" with banque_list=banque_list %}
<br /> <br />

View file

@ -7,7 +7,7 @@
<h2>Liste des types de paiements</h2> <h2>Liste des types de paiements</h2>
{% if is_trez %} {% 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: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 %} {% endif %}
{% include "cotisations/aff_paiement.html" with paiement_list=paiement_list %} {% include "cotisations/aff_paiement.html" with paiement_list=paiement_list %}
<br /> <br />

View file

@ -20,6 +20,10 @@ urlpatterns = [
url(r'^index_article/$', views.index_article, name='index-article'), url(r'^index_article/$', views.index_article, name='index-article'),
url(r'^index_banque/$', views.index_banque, name='index-banque'), url(r'^index_banque/$', views.index_banque, name='index-banque'),
url(r'^index_paiement/$', views.index_paiement, name='index-paiement'), 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'^control/$', views.control, name='control'),
url(r'^$', views.index, name='index'), 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.auth.decorators import login_required, permission_required
from django.contrib import messages from django.contrib import messages
from django.db.models import Max, ProtectedError from django.db.models import Max, ProtectedError
from django.db import transaction
from django.forms import modelformset_factory, formset_factory from django.forms import modelformset_factory, formset_factory
import os import os
from reversion import revisions as reversion
from .models import Facture, Article, Vente, Cotisation, Paiement, Banque from .models import Facture, Article, Vente, Cotisation, Paiement, Banque
from .forms import NewFactureForm, TrezEditFactureForm, EditFactureForm, ArticleForm, DelArticleForm, PaiementForm, DelPaiementForm, BanqueForm, DelBanqueForm, NewFactureFormPdf, SelectArticleForm 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 articles = article_formset
# Si au moins un article est rempli # Si au moins un article est rempli
if any(art.cleaned_data for art in articles): if any(art.cleaned_data for art in articles):
with transaction.atomic(), reversion.create_revision():
new_facture.save() new_facture.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
for art_item in articles: for art_item in articles:
if art_item.cleaned_data: if art_item.cleaned_data:
article = art_item.cleaned_data['article'] article = art_item.cleaned_data['article']
quantity = art_item.cleaned_data['quantity'] 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 = Vente.objects.create(facture=new_facture, name=article.name, prix=article.prix, iscotisation=article.iscotisation, duration=article.duration, number=quantity)
with transaction.atomic(), reversion.create_revision():
new_vente.save() new_vente.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
if art_item.cleaned_data['article'].iscotisation: if art_item.cleaned_data['article'].iscotisation:
create_cotis(new_vente, user, art_item.cleaned_data['article'].duration*art_item.cleaned_data['quantity']) 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): 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_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) vente_form = vente_form_set(request.POST or None, queryset=ventes_objects)
if facture_form.is_valid() and vente_form.is_valid(): if facture_form.is_valid() and vente_form.is_valid():
with transaction.atomic(), reversion.create_revision():
facture_form.save() facture_form.save()
vente_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") messages.success(request, "La facture a bien été modifiée")
return redirect("/cotisations/") return redirect("/cotisations/")
return form({'factureform': facture_form, 'venteform': vente_form}, 'cotisations/edit_facture.html', request) 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") messages.error(request, "Vous ne pouvez pas editer une facture controlée ou invalidée par le trésorier")
return redirect("/cotisations/") return redirect("/cotisations/")
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision():
facture.delete() facture.delete()
reversion.set_user(request.user)
messages.success(request, "La facture a été détruite") messages.success(request, "La facture a été détruite")
return redirect("/cotisations/") return redirect("/cotisations/")
return form({'objet': facture, 'objet_name': 'facture'}, 'cotisations/delete.html', request) return form({'objet': facture, 'objet_name': 'facture'}, 'cotisations/delete.html', request)
@ -158,7 +171,10 @@ def del_facture(request, factureid):
def add_article(request): def add_article(request):
article = ArticleForm(request.POST or None) article = ArticleForm(request.POST or None)
if article.is_valid(): if article.is_valid():
with transaction.atomic(), reversion.create_revision():
article.save() article.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "L'article a été ajouté") messages.success(request, "L'article a été ajouté")
return redirect("/cotisations/index_article/") return redirect("/cotisations/index_article/")
return form({'factureform': article}, 'cotisations/facture.html', request) return form({'factureform': article}, 'cotisations/facture.html', request)
@ -173,7 +189,10 @@ def edit_article(request, articleid):
return redirect("/cotisations/index_article/") return redirect("/cotisations/index_article/")
article = ArticleForm(request.POST or None, instance=article_instance) article = ArticleForm(request.POST or None, instance=article_instance)
if article.is_valid(): if article.is_valid():
with transaction.atomic(), reversion.create_revision():
article.save() 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é") messages.success(request, "Type d'article modifié")
return redirect("/cotisations/index_article/") return redirect("/cotisations/index_article/")
return form({'factureform': article}, 'cotisations/facture.html', request) return form({'factureform': article}, 'cotisations/facture.html', request)
@ -184,7 +203,9 @@ def del_article(request):
article = DelArticleForm(request.POST or None) article = DelArticleForm(request.POST or None)
if article.is_valid(): if article.is_valid():
article_del = article.cleaned_data['articles'] article_del = article.cleaned_data['articles']
with transaction.atomic(), reversion.create_revision():
article_del.delete() article_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le/les articles ont été supprimé") messages.success(request, "Le/les articles ont été supprimé")
return redirect("/cotisations/index_article") return redirect("/cotisations/index_article")
return form({'factureform': article}, 'cotisations/facture.html', request) return form({'factureform': article}, 'cotisations/facture.html', request)
@ -194,7 +215,10 @@ def del_article(request):
def add_paiement(request): def add_paiement(request):
paiement = PaiementForm(request.POST or None) paiement = PaiementForm(request.POST or None)
if paiement.is_valid(): if paiement.is_valid():
with transaction.atomic(), reversion.create_revision():
paiement.save() paiement.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Le moyen de paiement a été ajouté") messages.success(request, "Le moyen de paiement a été ajouté")
return redirect("/cotisations/index_paiement/") return redirect("/cotisations/index_paiement/")
return form({'factureform': paiement}, 'cotisations/facture.html', request) return form({'factureform': paiement}, 'cotisations/facture.html', request)
@ -209,7 +233,10 @@ def edit_paiement(request, paiementid):
return redirect("/cotisations/index_paiement/") return redirect("/cotisations/index_paiement/")
paiement = PaiementForm(request.POST or None, instance=paiement_instance) paiement = PaiementForm(request.POST or None, instance=paiement_instance)
if paiement.is_valid(): if paiement.is_valid():
with transaction.atomic(), reversion.create_revision():
paiement.save() 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é") messages.success(request, "Type de paiement modifié")
return redirect("/cotisations/index_paiement/") return redirect("/cotisations/index_paiement/")
return form({'factureform': paiement}, 'cotisations/facture.html', request) return form({'factureform': paiement}, 'cotisations/facture.html', request)
@ -222,7 +249,10 @@ def del_paiement(request):
paiement_dels = paiement.cleaned_data['paiements'] paiement_dels = paiement.cleaned_data['paiements']
for paiement_del in paiement_dels: for paiement_del in paiement_dels:
try: try:
with transaction.atomic(), reversion.create_revision():
paiement_del.delete() paiement_del.delete()
reversion.set_user(request.user)
reversion.set_comment("Destruction")
messages.success(request, "Le moyen de paiement a été supprimé") messages.success(request, "Le moyen de paiement a été supprimé")
except ProtectedError: except ProtectedError:
messages.error(request, "Le moyen de paiement %s est affecté à au moins une facture, vous ne pouvez pas le supprimer" % paiement_del) 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): def add_banque(request):
banque = BanqueForm(request.POST or None) banque = BanqueForm(request.POST or None)
if banque.is_valid(): if banque.is_valid():
with transaction.atomic(), reversion.create_revision():
banque.save() banque.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "La banque a été ajoutée") messages.success(request, "La banque a été ajoutée")
return redirect("/cotisations/index_banque/") return redirect("/cotisations/index_banque/")
return form({'factureform': banque}, 'cotisations/facture.html', request) return form({'factureform': banque}, 'cotisations/facture.html', request)
@ -249,7 +282,10 @@ def edit_banque(request, banqueid):
return redirect("/cotisations/index_banque/") return redirect("/cotisations/index_banque/")
banque = BanqueForm(request.POST or None, instance=banque_instance) banque = BanqueForm(request.POST or None, instance=banque_instance)
if banque.is_valid(): if banque.is_valid():
with transaction.atomic(), reversion.create_revision():
banque.save() 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") messages.success(request, "Banque modifiée")
return redirect("/cotisations/index_banque/") return redirect("/cotisations/index_banque/")
return form({'factureform': banque}, 'cotisations/facture.html', request) return form({'factureform': banque}, 'cotisations/facture.html', request)
@ -262,7 +298,10 @@ def del_banque(request):
banque_dels = banque.cleaned_data['banques'] banque_dels = banque.cleaned_data['banques']
for banque_del in banque_dels: for banque_del in banque_dels:
try: try:
with transaction.atomic(), reversion.create_revision():
banque_del.delete() banque_del.delete()
reversion.set_user(request.user)
reversion.set_comment("Destruction")
messages.success(request, "La banque a été supprimée") messages.success(request, "La banque a été supprimée")
except ProtectedError: except ProtectedError:
messages.error(request, "La banque %s est affectée à au moins une facture, vous ne pouvez pas la supprimer" % banque_del) 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): def index(request):
facture_list = Facture.objects.order_by('date').reverse() facture_list = Facture.objects.order_by('date').reverse()
return render(request, 'cotisations/index.html', {'facture_list': facture_list}) 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 django.contrib import admin
from reversion.admin import VersionAdmin
from .models import Machine, MachineType, IpList, Interface, Extension from .models import Machine, MachineType, IpList, Interface, Extension
class MachineAdmin(admin.ModelAdmin): class MachineAdmin(VersionAdmin):
list_display = ('user','name','active') list_display = ('user','name','active')
class MachineTypeAdmin(admin.ModelAdmin): class MachineTypeAdmin(VersionAdmin):
list_display = ('type','extension') list_display = ('type','extension')
class ExtensionAdmin(admin.ModelAdmin): class ExtensionAdmin(VersionAdmin):
list_display = ('name',) list_display = ('name',)
class IpListAdmin(admin.ModelAdmin): class IpListAdmin(VersionAdmin):
list_display = ('ipv4',) list_display = ('ipv4',)
class InterfaceAdmin(admin.ModelAdmin): class InterfaceAdmin(VersionAdmin):
list_display = ('machine','type','dns','mac_address','ipv4','details') list_display = ('machine','type','dns','mac_address','ipv4','details')
admin.site.register(Machine, MachineAdmin) admin.site.register(Machine, MachineAdmin)

View file

@ -3,12 +3,14 @@
<tr> <tr>
<th>Extension</th> <th>Extension</th>
<th></th> <th></th>
<th></th>
</tr> </tr>
</thead> </thead>
{% for extension in extension_list %} {% for extension in extension_list %}
<tr> <tr>
<td>{{ extension.name }}</td> <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>{% 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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -9,7 +9,8 @@
<tr> <tr>
<td><p>{{ machine.user }}</p> <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-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"> <td><table class="table table-striped">
<thead> <thead>
<tr> <tr>
@ -33,6 +34,7 @@
</button> </button>
<ul class="dropdown-menu" aria-labelledby="editioninterface"> <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: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> <li><a href="{% url 'machines:del-interface' interface.id %}"><i class="glyphicon glyphicon-trash"></i> Supprimer</a></li>
</ul></div></td> </ul></div></td>
</tr> </tr>

View file

@ -4,6 +4,7 @@
<th>Type de machine</th> <th>Type de machine</th>
<th>Extension</th> <th>Extension</th>
<th></th> <th></th>
<th></th>
</tr> </tr>
</thead> </thead>
{% for type in machinetype_list %} {% for type in machinetype_list %}
@ -11,6 +12,7 @@
<td>{{ type.type }}</td> <td>{{ type.type }}</td>
<td>{{ type.extension }}</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>{% 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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -7,7 +7,7 @@
<h2>Liste des extensions</h2> <h2>Liste des extensions</h2>
{% if is_infra %} {% 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: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 %} {% endif %}
{% include "machines/aff_extension.html" with extension_list=extension_list %} {% include "machines/aff_extension.html" with extension_list=extension_list %}
<br /> <br />

View file

@ -7,7 +7,7 @@
<h2>Liste des types de machines</h2> <h2>Liste des types de machines</h2>
{% if is_infra %} {% 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: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 %} {% endif %}
{% include "machines/aff_machinetype.html" with machinetype_list=machinetype_list %} {% include "machines/aff_machinetype.html" with machinetype_list=machinetype_list %}
<br /> <br />

View file

@ -16,6 +16,10 @@ urlpatterns = [
url(r'^edit_extension/(?P<extensionid>[0-9]+)$', views.edit_extension, name='edit-extension'), 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'^del_extension/$', views.del_extension, name='del-extension'),
url(r'^index_extension/$', views.index_extension, name='index-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'^$', views.index, name='index'),
url(r'^rest/mac-ip/$', views.mac_ip, name='mac-ip'), url(r'^rest/mac-ip/$', views.mac_ip, name='mac-ip'),
url(r'^rest/dns-ip/$', views.dns_ip, name='dns-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.contrib.auth.decorators import login_required, permission_required
from django.db.models import ProtectedError from django.db.models import ProtectedError
from django.forms import ValidationError from django.forms import ValidationError
from django.db import transaction
from rest_framework.renderers import JSONRenderer from rest_framework.renderers import JSONRenderer
from machines.serializers import InterfaceSerializer from machines.serializers import InterfaceSerializer
from reversion import revisions as reversion
import re import re
@ -52,6 +54,8 @@ def assign_ips(user):
for machine in machines: for machine in machines:
if not machine.ipv4: if not machine.ipv4:
interface = assign_ipv4(machine) interface = assign_ipv4(machine)
with transaction.atomic(), reversion.create_revision():
reversion.set_comment("Assignation ipv4")
interface.save() interface.save()
return return
@ -68,6 +72,8 @@ def assign_ipv4(interface):
def unassign_ipv4(interface): def unassign_ipv4(interface):
interface.ipv4 = None interface.ipv4 = None
with transaction.atomic(), reversion.create_revision():
reversion.set_comment("Désassignation ipv4")
interface.save() interface.save()
def form(ctx, template, request): def form(ctx, template, request):
@ -92,13 +98,19 @@ def new_machine(request, userid):
new_machine.user = user new_machine.user = user
new_interface = interface.save(commit=False) new_interface = interface.save(commit=False)
if full_domain_validator(request, new_interface): if full_domain_validator(request, new_interface):
with transaction.atomic(), reversion.create_revision():
new_machine.save() new_machine.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_interface.machine = new_machine new_interface.machine = new_machine
if free_ip() and not new_interface.ipv4: if free_ip() and not new_interface.ipv4:
new_interface = assign_ipv4(new_interface) new_interface = assign_ipv4(new_interface)
elif not new_interface.ipv4: elif not new_interface.ipv4:
messages.error(request, u"Il n'y a plus d'ip disponibles") messages.error(request, u"Il n'y a plus d'ip disponibles")
with transaction.atomic(), reversion.create_revision():
new_interface.save() new_interface.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "La machine a été crée") messages.success(request, "La machine a été crée")
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
return form({'machineform': machine, 'interfaceform': interface}, 'machines/machine.html', request) 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_interface = interface_form.save(commit=False)
new_machine = machine_form.save(commit=False) new_machine = machine_form.save(commit=False)
if full_domain_validator(request, new_interface): if full_domain_validator(request, new_interface):
with transaction.atomic(), reversion.create_revision():
new_machine.save() 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() 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") messages.success(request, "La machine a été modifiée")
return redirect("/users/profil/" + str(interface.machine.user.id)) return redirect("/users/profil/" + str(interface.machine.user.id))
return form({'machineform': machine_form, 'interfaceform': interface_form}, 'machines/machine.html', request) 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") 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)) return redirect("/users/profil/" + str(request.user.id))
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision():
machine.delete() machine.delete()
reversion.set_user(request.user)
messages.success(request, "La machine a été détruite") messages.success(request, "La machine a été détruite")
return redirect("/users/profil/" + str(request.user.id)) return redirect("/users/profil/" + str(request.user.id))
return form({'objet': machine, 'objet_name': 'machine'}, 'machines/delete.html', request) 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) new_interface = assign_ipv4(new_interface)
elif not new_interface.ipv4: elif not new_interface.ipv4:
messages.error(request, u"Il n'y a plus d'ip disponibles") messages.error(request, u"Il n'y a plus d'ip disponibles")
with transaction.atomic(), reversion.create_revision():
new_interface.save() new_interface.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "L'interface a été ajoutée") messages.success(request, "L'interface a été ajoutée")
return redirect("/users/profil/" + str(request.user.id)) return redirect("/users/profil/" + str(request.user.id))
return form({'interfaceform': interface_form}, 'machines/machine.html', request) 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") 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)) return redirect("/users/profil/" + str(request.user.id))
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision():
interface.delete() interface.delete()
reversion.set_user(request.user)
messages.success(request, "L'interface a été détruite") messages.success(request, "L'interface a été détruite")
return redirect("/users/profil/" + str(request.user.id)) return redirect("/users/profil/" + str(request.user.id))
return form({'objet': interface, 'objet_name': 'interface'}, 'machines/delete.html', request) return form({'objet': interface, 'objet_name': 'interface'}, 'machines/delete.html', request)
@ -193,7 +218,10 @@ def del_interface(request, interfaceid):
def add_machinetype(request): def add_machinetype(request):
machinetype = MachineTypeForm(request.POST or None) machinetype = MachineTypeForm(request.POST or None)
if machinetype.is_valid(): if machinetype.is_valid():
with transaction.atomic(), reversion.create_revision():
machinetype.save() machinetype.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Ce type de machine a été ajouté") messages.success(request, "Ce type de machine a été ajouté")
return redirect("/machines/index_machinetype") return redirect("/machines/index_machinetype")
return form({'machineform': machinetype, 'interfaceform': None}, 'machines/machine.html', request) return form({'machineform': machinetype, 'interfaceform': None}, 'machines/machine.html', request)
@ -208,7 +236,10 @@ def edit_machinetype(request, machinetypeid):
return redirect("/machines/index_machinetype/") return redirect("/machines/index_machinetype/")
machinetype = MachineTypeForm(request.POST or None, instance=machinetype_instance) machinetype = MachineTypeForm(request.POST or None, instance=machinetype_instance)
if machinetype.is_valid(): if machinetype.is_valid():
with transaction.atomic(), reversion.create_revision():
machinetype.save() 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é") messages.success(request, "Type de machine modifié")
return redirect("/machines/index_machinetype/") return redirect("/machines/index_machinetype/")
return form({'machineform': machinetype}, 'machines/machine.html', request) return form({'machineform': machinetype}, 'machines/machine.html', request)
@ -221,7 +252,9 @@ def del_machinetype(request):
machinetype_dels = machinetype.cleaned_data['machinetypes'] machinetype_dels = machinetype.cleaned_data['machinetypes']
for machinetype_del in machinetype_dels: for machinetype_del in machinetype_dels:
try: try:
with transaction.atomic(), reversion.create_revision():
machinetype_del.delete() machinetype_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le type de machine a été supprimé") messages.success(request, "Le type de machine a été supprimé")
except ProtectedError: 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) 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): def add_extension(request):
extension = ExtensionForm(request.POST or None) extension = ExtensionForm(request.POST or None)
if extension.is_valid(): if extension.is_valid():
with transaction.atomic(), reversion.create_revision():
extension.save() extension.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cette extension a été ajoutée") messages.success(request, "Cette extension a été ajoutée")
return redirect("/machines/index_extension") return redirect("/machines/index_extension")
return form({'machineform': extension, 'interfaceform': None}, 'machines/machine.html', request) return form({'machineform': extension, 'interfaceform': None}, 'machines/machine.html', request)
@ -248,7 +284,10 @@ def edit_extension(request, extensionid):
return redirect("/machines/index_extension/") return redirect("/machines/index_extension/")
extension = ExtensionForm(request.POST or None, instance=extension_instance) extension = ExtensionForm(request.POST or None, instance=extension_instance)
if extension.is_valid(): if extension.is_valid():
with transaction.atomic(), reversion.create_revision():
extension.save() 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") messages.success(request, "Extension modifiée")
return redirect("/machines/index_extension/") return redirect("/machines/index_extension/")
return form({'machineform': extension}, 'machines/machine.html', request) return form({'machineform': extension}, 'machines/machine.html', request)
@ -261,7 +300,9 @@ def del_extension(request):
extension_dels = extension.cleaned_data['extensions'] extension_dels = extension.cleaned_data['extensions']
for extension_del in extension_dels: for extension_del in extension_dels:
try: try:
with transaction.atomic(), reversion.create_revision():
extension_del.delete() extension_del.delete()
reversion.set_user(request.user)
messages.success(request, "L'extension a été supprimée") messages.success(request, "L'extension a été supprimée")
except ProtectedError: 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) 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') extension_list = Extension.objects.order_by('name')
return render(request, 'machines/index_extension.html', {'extension_list':extension_list}) 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 """ """ Framework Rest """
class JSONResponse(HttpResponse): class JSONResponse(HttpResponse):

View file

@ -1,6 +1,7 @@
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin 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 .models import User, School, Right, ListRight, Ban, Whitelist, Request
from .forms import UserChangeForm, UserCreationForm from .forms import UserChangeForm, UserCreationForm
@ -18,11 +19,11 @@ class UserAdmin(admin.ModelAdmin):
) )
class SchoolAdmin(admin.ModelAdmin): class SchoolAdmin(VersionAdmin):
list_display = ('name',) list_display = ('name',)
class ListRightAdmin(admin.ModelAdmin): class ListRightAdmin(VersionAdmin):
list_display = ('listright',) list_display = ('listright',)
@ -32,15 +33,15 @@ class RightAdmin(admin.ModelAdmin):
class RequestAdmin(admin.ModelAdmin): class RequestAdmin(admin.ModelAdmin):
list_display = ('user', 'type', 'created_at', 'expires_at') list_display = ('user', 'type', 'created_at', 'expires_at')
class BanAdmin(admin.ModelAdmin): class BanAdmin(VersionAdmin):
list_display = ('user', 'raison', 'date_start', 'date_end') list_display = ('user', 'raison', 'date_start', 'date_end')
class WhitelistAdmin(admin.ModelAdmin): class WhitelistAdmin(VersionAdmin):
list_display = ('user', 'raison', 'date_start', 'date_end') list_display = ('user', 'raison', 'date_start', 'date_end')
class UserAdmin(BaseUserAdmin): class UserAdmin(VersionAdmin, BaseUserAdmin):
# The forms to add and change user instances # The forms to add and change user instances
form = UserChangeForm form = UserChangeForm
add_form = UserCreationForm add_form = UserCreationForm

View file

@ -6,6 +6,7 @@
<th>Date de début</th> <th>Date de début</th>
<th>Date de fin</th> <th>Date de fin</th>
<th></th> <th></th>
<th></th>
</tr> </tr>
</thead> </thead>
{% for ban in ban_list %} {% for ban in ban_list %}
@ -15,6 +16,7 @@
<td>{{ ban.date_start }}</td> <td>{{ ban.date_start }}</td>
<td>{{ ban.date_end }}</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>{% 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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -3,12 +3,14 @@
<tr> <tr>
<th>Etablissement</th> <th>Etablissement</th>
<th></th> <th></th>
<th></th>
</tr> </tr>
</thead> </thead>
{% for school in school_list %} {% for school in school_list %}
<tr> <tr>
<td>{{ school.name }}</td> <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-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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -6,6 +6,7 @@
<th>Date de début</th> <th>Date de début</th>
<th>Date de fin</th> <th>Date de fin</th>
<th></th> <th></th>
<th></th>
</tr> </tr>
</thead> </thead>
{% for whitelist in white_list %} {% for whitelist in white_list %}
@ -15,6 +16,7 @@
<td>{{ whitelist.date_start }}</td> <td>{{ whitelist.date_start }}</td>
<td>{{ whitelist.date_end }}</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>{% 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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -6,7 +6,7 @@
{% block content %} {% block content %}
<h2>Liste des Établissements</h2> <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: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 %} {% include "users/aff_schools.html" with school_list=school_list %}
<br /> <br />
<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> <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> {% 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-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 />
<br /> <br />
<table class="table table-striped"> <table class="table table-striped">

View file

@ -23,6 +23,10 @@ urlpatterns = [
url(r'^mon_profil/$', views.mon_profil, name='mon-profil'), 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'^process/(?P<token>[a-z0-9]{32})/$', views.process, name='process'),
url(r'^reset_password/$', views.reset_password, name='reset-password'), 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'), 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.core.mail import send_mail
from django.utils import timezone from django.utils import timezone
from django.core.urlresolvers import reverse 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 User, Right, Ban, Whitelist, School, Request
from users.models import DelRightForm, BanForm, WhitelistForm, DelSchoolForm from users.models import DelRightForm, BanForm, WhitelistForm, DelSchoolForm
from users.models import InfoForm, BaseInfoForm, StateForm, RightForm, SchoolForm 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) return form({'userform': u_form}, 'users/user.html', request)
user.set_password(u_form.cleaned_data['passwd1']) user.set_password(u_form.cleaned_data['passwd1'])
user.pwd_ntlm = hashNT(u_form.cleaned_data['passwd1']) user.pwd_ntlm = hashNT(u_form.cleaned_data['passwd1'])
with transaction.atomic(), reversion.create_revision():
user.save() user.save()
reversion.set_comment("Réinitialisation du mot de passe")
messages.success(request, "Le mot de passe a changé") messages.success(request, "Le mot de passe a changé")
if req: if req:
req.delete() req.delete()
@ -78,14 +82,17 @@ def new_user(request):
user = InfoForm(request.POST or None) user = InfoForm(request.POST or None)
if user.is_valid(): if user.is_valid():
user = user.save(commit=False) user = user.save(commit=False)
with transaction.atomic(), reversion.create_revision():
user.save() user.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
req = Request() req = Request()
req.type = Request.PASSWD req.type = Request.PASSWD
req.user = user req.user = user
req.save() req.save()
reset_passwd_mail(req, request) 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) 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) return form({'userform': user}, 'users/user.html', request)
@login_required @login_required
@ -103,7 +110,10 @@ def edit_info(request, userid):
else: else:
user = InfoForm(request.POST or None, instance=user) user = InfoForm(request.POST or None, instance=user)
if user.is_valid(): if user.is_valid():
with transaction.atomic(), reversion.create_revision():
user.save() 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é") messages.success(request, "L'user a bien été modifié")
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
return form({'userform': user}, 'users/user.html', request) return form({'userform': user}, 'users/user.html', request)
@ -123,7 +133,10 @@ def state(request, userid):
archive(user) archive(user)
else: else:
unarchive(user) unarchive(user)
with transaction.atomic(), reversion.create_revision():
state.save() 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") messages.success(request, "Etat changé avec succès")
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
return form({'userform': state}, 'users/user.html', request) return form({'userform': state}, 'users/user.html', request)
@ -188,7 +201,10 @@ def add_ban(request, userid):
ban_instance = Ban(user=user) ban_instance = Ban(user=user)
ban = BanForm(request.POST or None, instance=ban_instance) ban = BanForm(request.POST or None, instance=ban_instance)
if ban.is_valid(): if ban.is_valid():
with transaction.atomic(), reversion.create_revision():
ban.save() ban.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Bannissement ajouté") messages.success(request, "Bannissement ajouté")
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
if user.is_ban(): if user.is_ban():
@ -208,7 +224,10 @@ def edit_ban(request, banid):
return redirect("/users/") return redirect("/users/")
ban = BanForm(request.POST or None, instance=ban_instance) ban = BanForm(request.POST or None, instance=ban_instance)
if ban.is_valid(): if ban.is_valid():
with transaction.atomic(), reversion.create_revision():
ban.save() 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é") messages.success(request, "Bannissement modifié")
return redirect("/users/") return redirect("/users/")
return form({'userform': ban}, 'users/user.html', request) return form({'userform': ban}, 'users/user.html', request)
@ -224,7 +243,10 @@ def add_whitelist(request, userid):
whitelist_instance = Whitelist(user=user) whitelist_instance = Whitelist(user=user)
whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance) whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance)
if whitelist.is_valid(): if whitelist.is_valid():
with transaction.atomic(), reversion.create_revision():
whitelist.save() whitelist.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Accès à titre gracieux accordé") messages.success(request, "Accès à titre gracieux accordé")
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
if is_whitelisted(user): if is_whitelisted(user):
@ -244,7 +266,10 @@ def edit_whitelist(request, whitelistid):
return redirect("/users/") return redirect("/users/")
whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance) whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance)
if whitelist.is_valid(): if whitelist.is_valid():
with transaction.atomic(), reversion.create_revision():
whitelist.save() 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") messages.success(request, "Whitelist modifiée")
return redirect("/users/") return redirect("/users/")
return form({'userform': whitelist}, 'users/user.html', request) return form({'userform': whitelist}, 'users/user.html', request)
@ -254,7 +279,10 @@ def edit_whitelist(request, whitelistid):
def add_school(request): def add_school(request):
school = SchoolForm(request.POST or None) school = SchoolForm(request.POST or None)
if school.is_valid(): if school.is_valid():
with transaction.atomic(), reversion.create_revision():
school.save() school.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "L'établissement a été ajouté") messages.success(request, "L'établissement a été ajouté")
return redirect("/users/index_school/") return redirect("/users/index_school/")
return form({'userform': school}, 'users/user.html', request) return form({'userform': school}, 'users/user.html', request)
@ -269,7 +297,10 @@ def edit_school(request, schoolid):
return redirect("/users/") return redirect("/users/")
school = SchoolForm(request.POST or None, instance=school_instance) school = SchoolForm(request.POST or None, instance=school_instance)
if school.is_valid(): if school.is_valid():
with transaction.atomic(), reversion.create_revision():
school.save() 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é") messages.success(request, "Établissement modifié")
return redirect("/users/index_school/") return redirect("/users/index_school/")
return form({'userform': school}, 'users/user.html', request) return form({'userform': school}, 'users/user.html', request)
@ -282,7 +313,9 @@ def del_school(request):
school_dels = school.cleaned_data['schools'] school_dels = school.cleaned_data['schools']
for school_del in school_dels: for school_del in school_dels:
try: try:
with transaction.atomic(), reversion.create_revision():
school_del.delete() school_del.delete()
reversion.set_comment("Destruction")
messages.success(request, "L'établissement a été supprimé") messages.success(request, "L'établissement a été supprimé")
except ProtectedError: except ProtectedError:
messages.error( messages.error(
@ -320,6 +353,48 @@ def index_school(request):
school_list = School.objects.order_by('name') school_list = School.objects.order_by('name')
return render(request, 'users/index_schools.html', {'school_list':school_list}) 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 @login_required
def mon_profil(request): def mon_profil(request):
return redirect("/users/profil/" + str(request.user.id)) return redirect("/users/profil/" + str(request.user.id))