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

Merge branch 'aff_port_naturel' into 'master'

Aff port naturel

See merge request nounous/re2o!21
This commit is contained in:
Gabriel Detraz 2018-04-02 20:21:01 +02:00
commit b748a3003a
23 changed files with 1077 additions and 706 deletions

View file

@ -45,9 +45,9 @@ from preferences.models import OptionalUser
from users.models import User from users.models import User
from re2o.field_permissions import FieldPermissionFormMixin from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
class NewFactureForm(FormRevMixin, ModelForm):
class NewFactureForm(ModelForm):
"""Creation d'une facture, moyen de paiement, banque et numero """Creation d'une facture, moyen de paiement, banque et numero
de cheque""" de cheque"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -96,7 +96,7 @@ class CreditSoldeForm(NewFactureForm):
montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True) montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True)
class SelectUserArticleForm(Form): class SelectUserArticleForm(FormRevMixin, Form):
"""Selection d'un article lors de la creation d'une facture""" """Selection d'un article lors de la creation d'une facture"""
article = forms.ModelChoiceField( article = forms.ModelChoiceField(
queryset=Article.objects.filter(Q(type_user='All') | Q(type_user='Adherent')), queryset=Article.objects.filter(Q(type_user='All') | Q(type_user='Adherent')),
@ -158,7 +158,7 @@ class EditFactureForm(FieldPermissionFormMixin, NewFactureForm):
self.fields['valid'].label = 'Validité de la facture' self.fields['valid'].label = 'Validité de la facture'
class ArticleForm(ModelForm): class ArticleForm(FormRevMixin, ModelForm):
"""Creation d'un article. Champs : nom, cotisation, durée""" """Creation d'un article. Champs : nom, cotisation, durée"""
class Meta: class Meta:
model = Article model = Article
@ -170,7 +170,7 @@ class ArticleForm(ModelForm):
self.fields['name'].label = "Désignation de l'article" self.fields['name'].label = "Désignation de l'article"
class DelArticleForm(Form): class DelArticleForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs articles en vente. Choix """Suppression d'un ou plusieurs articles en vente. Choix
parmis les modèles""" parmis les modèles"""
articles = forms.ModelMultipleChoiceField( articles = forms.ModelMultipleChoiceField(
@ -188,7 +188,7 @@ class DelArticleForm(Form):
self.fields['articles'].queryset = Article.objects.all() self.fields['articles'].queryset = Article.objects.all()
class PaiementForm(ModelForm): class PaiementForm(FormRevMixin, ModelForm):
"""Creation d'un moyen de paiement, champ text moyen et type """Creation d'un moyen de paiement, champ text moyen et type
permettant d'indiquer si il s'agit d'un chèque ou non pour le form""" permettant d'indiquer si il s'agit d'un chèque ou non pour le form"""
class Meta: class Meta:
@ -202,7 +202,7 @@ class PaiementForm(ModelForm):
self.fields['type_paiement'].label = 'Type de paiement à ajouter' self.fields['type_paiement'].label = 'Type de paiement à ajouter'
class DelPaiementForm(Form): class DelPaiementForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs moyens de paiements, selection """Suppression d'un ou plusieurs moyens de paiements, selection
parmis les models""" parmis les models"""
paiements = forms.ModelMultipleChoiceField( paiements = forms.ModelMultipleChoiceField(
@ -220,7 +220,7 @@ class DelPaiementForm(Form):
self.fields['paiements'].queryset = Paiement.objects.all() self.fields['paiements'].queryset = Paiement.objects.all()
class BanqueForm(ModelForm): class BanqueForm(FormRevMixin, ModelForm):
"""Creation d'une banque, field name""" """Creation d'une banque, field name"""
class Meta: class Meta:
model = Banque model = Banque
@ -232,7 +232,7 @@ class BanqueForm(ModelForm):
self.fields['name'].label = 'Banque à ajouter' self.fields['name'].label = 'Banque à ajouter'
class DelBanqueForm(Form): class DelBanqueForm(FormRevMixin, Form):
"""Selection d'une ou plusieurs banques, pour suppression""" """Selection d'une ou plusieurs banques, pour suppression"""
banques = forms.ModelMultipleChoiceField( banques = forms.ModelMultipleChoiceField(
queryset=Banque.objects.none(), queryset=Banque.objects.none(),
@ -283,7 +283,7 @@ class NewFactureSoldeForm(NewFactureForm):
return cleaned_data return cleaned_data
class RechargeForm(Form): class RechargeForm(FormRevMixin, Form):
value = forms.FloatField( value = forms.FloatField(
label='Valeur', label='Valeur',
min_value=0.01, min_value=0.01,

View file

@ -57,9 +57,10 @@ from django.utils import timezone
from machines.models import regen from machines.models import regen
from re2o.field_permissions import FieldPermissionModelMixin from re2o.field_permissions import FieldPermissionModelMixin
from re2o.mixins import AclMixin from re2o.mixins import AclMixin, RevMixin
class Facture(AclMixin, FieldPermissionModelMixin, models.Model):
class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
""" Définition du modèle des factures. Une facture regroupe une ou """ Définition du modèle des factures. Une facture regroupe une ou
plusieurs ventes, rattachée à un user, et reliée à un moyen de paiement plusieurs ventes, rattachée à un user, et reliée à un moyen de paiement
et si il y a lieu un numero pour les chèques. Possède les valeurs et si il y a lieu un numero pour les chèques. Possède les valeurs
@ -87,6 +88,11 @@ class Facture(AclMixin, FieldPermissionModelMixin, models.Model):
("change_all_facture", "Superdroit, peut modifier toutes les factures"), ("change_all_facture", "Superdroit, peut modifier toutes les factures"),
) )
def linked_objects(self):
"""Return linked objects : machine and domain.
Usefull in history display"""
return self.vente_set.all()
def prix(self): def prix(self):
"""Renvoie le prix brut sans les quantités. Méthode """Renvoie le prix brut sans les quantités. Méthode
dépréciée""" dépréciée"""
@ -180,7 +186,7 @@ def facture_post_delete(sender, **kwargs):
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
class Vente(AclMixin, models.Model): class Vente(RevMixin, AclMixin, models.Model):
"""Objet vente, contient une quantité, une facture parente, un nom, """Objet vente, contient une quantité, une facture parente, un nom,
un prix. Peut-être relié à un objet cotisation, via le boolean un prix. Peut-être relié à un objet cotisation, via le boolean
iscotisation""" iscotisation"""
@ -325,7 +331,7 @@ def vente_post_delete(sender, **kwargs):
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
class Article(AclMixin, models.Model): class Article(RevMixin, AclMixin, models.Model):
"""Liste des articles en vente : prix, nom, et attribut iscotisation """Liste des articles en vente : prix, nom, et attribut iscotisation
et duree si c'est une cotisation""" et duree si c'est une cotisation"""
PRETTY_NAME = "Articles en vente" PRETTY_NAME = "Articles en vente"
@ -381,7 +387,7 @@ class Article(AclMixin, models.Model):
return self.name return self.name
class Banque(AclMixin, models.Model): class Banque(RevMixin, AclMixin, models.Model):
"""Liste des banques""" """Liste des banques"""
PRETTY_NAME = "Banques enregistrées" PRETTY_NAME = "Banques enregistrées"
@ -396,7 +402,7 @@ class Banque(AclMixin, models.Model):
return self.name return self.name
class Paiement(AclMixin, models.Model): class Paiement(RevMixin, AclMixin, models.Model):
"""Moyens de paiement""" """Moyens de paiement"""
PRETTY_NAME = "Moyens de paiement" PRETTY_NAME = "Moyens de paiement"
PAYMENT_TYPES = ( PAYMENT_TYPES = (
@ -426,7 +432,7 @@ class Paiement(AclMixin, models.Model):
super(Paiement, self).save(*args, **kwargs) super(Paiement, self).save(*args, **kwargs)
class Cotisation(AclMixin, models.Model): class Cotisation(RevMixin, AclMixin, models.Model):
"""Objet cotisation, debut et fin, relié en onetoone à une vente""" """Objet cotisation, debut et fin, relié en onetoone à une vente"""
PRETTY_NAME = "Cotisations" PRETTY_NAME = "Cotisations"

View file

@ -39,8 +39,6 @@ from django.forms import modelformset_factory, formset_factory
from django.utils import timezone from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.debug import sensitive_variables from django.views.decorators.debug import sensitive_variables
from reversion import revisions as reversion
from reversion.models import Version
# Import des models, forms et fonctions re2o # Import des models, forms et fonctions re2o
from users.models import User from users.models import User
from re2o.settings import LOGO_PATH from re2o.settings import LOGO_PATH
@ -126,10 +124,7 @@ def new_facture(request, user, userid):
'users:profil', 'users:profil',
kwargs={'userid': userid} kwargs={'userid': userid}
)) ))
with transaction.atomic(), reversion.create_revision(): new_facture_instance.save()
new_facture_instance.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']
@ -142,10 +137,7 @@ def new_facture(request, user, userid):
duration=article.duration, duration=article.duration,
number=quantity 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 any(art_item.cleaned_data['article'].type_cotisation if any(art_item.cleaned_data['article'].type_cotisation
for art_item in articles if art_item.cleaned_data): for art_item in articles if art_item.cleaned_data):
messages.success( messages.success(
@ -257,13 +249,9 @@ def edit_facture(request, facture, factureid):
) )
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(): if facture_form.changed_data:
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(reverse('cotisations:index')) return redirect(reverse('cotisations:index'))
return form({ return form({
@ -278,9 +266,7 @@ def del_facture(request, facture, factureid):
"""Suppression d'une facture. Supprime en cascade les ventes """Suppression d'une facture. Supprime en cascade les ventes
et cotisations filles""" et cotisations filles"""
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(reverse('cotisations:index')) return redirect(reverse('cotisations:index'))
return form({ return form({
@ -297,21 +283,15 @@ def credit_solde(request, user, userid):
facture = CreditSoldeForm(request.POST or None) facture = CreditSoldeForm(request.POST or None)
if facture.is_valid(): if facture.is_valid():
facture_instance = facture.save(commit=False) facture_instance = facture.save(commit=False)
with transaction.atomic(), reversion.create_revision(): facture_instance.user = user
facture_instance.user = user facture_instance.save()
facture_instance.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_vente = Vente.objects.create( new_vente = Vente.objects.create(
facture=facture_instance, facture=facture_instance,
name="solde", name="solde",
prix=facture.cleaned_data['montant'], prix=facture.cleaned_data['montant'],
number=1 number=1
) )
with transaction.atomic(), reversion.create_revision(): new_vente.save()
new_vente.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Solde modifié") messages.success(request, "Solde modifié")
return redirect(reverse('cotisations:index')) return redirect(reverse('cotisations:index'))
return form({'factureform': facture, 'action_name' : 'Créditer'}, 'cotisations/facture.html', request) return form({'factureform': facture, 'action_name' : 'Créditer'}, 'cotisations/facture.html', request)
@ -329,10 +309,7 @@ def add_article(request):
PAS de conséquence sur les ventes déjà faites""" PAS de conséquence sur les ventes déjà faites"""
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(reverse('cotisations:index-article')) return redirect(reverse('cotisations:index-article'))
return form({'factureform': article, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request) return form({'factureform': article, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request)
@ -345,15 +322,9 @@ def edit_article(request, article_instance, articleid):
Réservé au trésorier""" Réservé au trésorier"""
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(): if article.changed_data:
article.save() article.save()
reversion.set_user(request.user) messages.success(request, "Type d'article modifié")
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in article.changed_data
)
)
messages.success(request, "Type d'article modifié")
return redirect(reverse('cotisations:index-article')) return redirect(reverse('cotisations:index-article'))
return form({'factureform': article, 'action_name' : 'Editer'}, 'cotisations/facture.html', request) return form({'factureform': article, 'action_name' : 'Editer'}, 'cotisations/facture.html', request)
@ -365,9 +336,7 @@ def del_article(request, instances):
article = DelArticleForm(request.POST or None, instances=instances) article = DelArticleForm(request.POST or None, instances=instances)
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(reverse('cotisations:index-article')) return redirect(reverse('cotisations:index-article'))
return form({'factureform': article, 'action_name' : 'Supprimer'}, 'cotisations/facture.html', request) return form({'factureform': article, 'action_name' : 'Supprimer'}, 'cotisations/facture.html', request)
@ -380,10 +349,7 @@ def add_paiement(request):
via foreign key""" via foreign key"""
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(reverse('cotisations:index-paiement')) return redirect(reverse('cotisations:index-paiement'))
return form({'factureform': paiement, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request) return form({'factureform': paiement, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request)
@ -395,15 +361,9 @@ def edit_paiement(request, paiement_instance, paiementid):
"""Edition d'un moyen de paiement""" """Edition d'un moyen de 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(): if paiement.changed_data:
paiement.save() paiement.save()
reversion.set_user(request.user) messages.success(request, "Type de paiement modifié")
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in paiement.changed_data
)
)
messages.success(request, "Type de paiement modifié")
return redirect(reverse('cotisations:index-paiement')) return redirect(reverse('cotisations:index-paiement'))
return form({'factureform': paiement, 'action_name' : 'Editer'}, 'cotisations/facture.html', request) return form({'factureform': paiement, 'action_name' : 'Editer'}, 'cotisations/facture.html', request)
@ -417,10 +377,7 @@ def del_paiement(request, instances):
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( messages.success(
request, request,
"Le moyen de paiement a été supprimé" "Le moyen de paiement a été supprimé"
@ -441,10 +398,7 @@ def add_banque(request):
"""Ajoute une banque à la liste des banques""" """Ajoute une banque à la liste des banques"""
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(reverse('cotisations:index-banque')) return redirect(reverse('cotisations:index-banque'))
return form({'factureform': banque, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request) return form({'factureform': banque, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request)
@ -456,15 +410,9 @@ def edit_banque(request, banque_instance, banqueid):
"""Edite le nom d'une banque""" """Edite le nom d'une 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(): if banque.changed_data:
banque.save() banque.save()
reversion.set_user(request.user) messages.success(request, "Banque modifiée")
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in banque.changed_data
)
)
messages.success(request, "Banque modifiée")
return redirect(reverse('cotisations:index-banque')) return redirect(reverse('cotisations:index-banque'))
return form({'factureform': banque, 'action_name' : 'Editer'}, 'cotisations/facture.html', request) return form({'factureform': banque, 'action_name' : 'Editer'}, 'cotisations/facture.html', request)
@ -478,10 +426,7 @@ def del_banque(request, instances):
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\ messages.error(request, "La banque %s est affectée à au moins\
@ -519,10 +464,7 @@ def control(request):
facture_list = paginator.page(paginator.num.pages) facture_list = paginator.page(paginator.num.pages)
controlform = controlform_set(request.POST or None, queryset=facture_list.object_list) controlform = controlform_set(request.POST or None, queryset=facture_list.object_list)
if controlform.is_valid(): if controlform.is_valid():
with transaction.atomic(), reversion.create_revision(): controlform.save()
controlform.save()
reversion.set_user(request.user)
reversion.set_comment("Controle trésorier")
return redirect(reverse('cotisations:control')) return redirect(reverse('cotisations:control'))
return render(request, 'cotisations/control.html', { return render(request, 'cotisations/control.html', {
'facture_list': facture_list, 'facture_list': facture_list,
@ -630,10 +572,7 @@ def new_facture_solde(request, userid):
'users:profil', 'users:profil',
kwargs={'userid': userid} kwargs={'userid': userid}
)) ))
with transaction.atomic(), reversion.create_revision(): facture.save()
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']
@ -646,10 +585,7 @@ def new_facture_solde(request, userid):
duration=article.duration, duration=article.duration,
number=quantity 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 any(art_item.cleaned_data['article'].type_cotisation if any(art_item.cleaned_data['article'].type_cotisation
for art_item in articles if art_item.cleaned_data): for art_item in articles if art_item.cleaned_data):
messages.success( messages.success(

View file

@ -39,6 +39,7 @@ from django.forms import ModelForm, Form
from django import forms from django import forms
from re2o.field_permissions import FieldPermissionFormMixin from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
from .models import ( from .models import (
Domain, Domain,
@ -61,7 +62,7 @@ from .models import (
) )
class EditMachineForm(FieldPermissionFormMixin, ModelForm): class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Formulaire d'édition d'une machine""" """Formulaire d'édition d'une machine"""
class Meta: class Meta:
model = Machine model = Machine
@ -79,7 +80,7 @@ class NewMachineForm(EditMachineForm):
fields = ['name'] fields = ['name']
class EditInterfaceForm(FieldPermissionFormMixin, ModelForm): class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Edition d'une interface. Edition complète""" """Edition d'une interface. Edition complète"""
class Meta: class Meta:
model = Interface model = Interface
@ -125,7 +126,7 @@ class AddInterfaceForm(EditInterfaceForm):
fields = ['type', 'ipv4', 'mac_address', 'details'] fields = ['type', 'ipv4', 'mac_address', 'details']
class AliasForm(ModelForm): class AliasForm(FormRevMixin, ModelForm):
"""Ajout d'un alias (et edition), CNAME, contenant nom et extension""" """Ajout d'un alias (et edition), CNAME, contenant nom et extension"""
class Meta: class Meta:
model = Domain model = Domain
@ -142,7 +143,7 @@ class AliasForm(ModelForm):
) )
class DomainForm(ModelForm): class DomainForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un enregistrement de nom, relié à interface""" """Ajout et edition d'un enregistrement de nom, relié à interface"""
class Meta: class Meta:
model = Domain model = Domain
@ -158,7 +159,7 @@ class DomainForm(ModelForm):
super(DomainForm, self).__init__(*args, prefix=prefix, **kwargs) super(DomainForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelAliasForm(Form): class DelAliasForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs objets alias""" """Suppression d'un ou plusieurs objets alias"""
alias = forms.ModelMultipleChoiceField( alias = forms.ModelMultipleChoiceField(
queryset=Domain.objects.all(), queryset=Domain.objects.all(),
@ -174,7 +175,7 @@ class DelAliasForm(Form):
) )
class MachineTypeForm(ModelForm): class MachineTypeForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un machinetype, relié à un iptype""" """Ajout et edition d'un machinetype, relié à un iptype"""
class Meta: class Meta:
model = MachineType model = MachineType
@ -187,7 +188,7 @@ class MachineTypeForm(ModelForm):
self.fields['ip_type'].label = "Type d'ip relié" self.fields['ip_type'].label = "Type d'ip relié"
class DelMachineTypeForm(Form): class DelMachineTypeForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs machinetype""" """Suppression d'un ou plusieurs machinetype"""
machinetypes = forms.ModelMultipleChoiceField( machinetypes = forms.ModelMultipleChoiceField(
queryset=MachineType.objects.none(), queryset=MachineType.objects.none(),
@ -204,7 +205,7 @@ class DelMachineTypeForm(Form):
self.fields['machinetypes'].queryset = MachineType.objects.all() self.fields['machinetypes'].queryset = MachineType.objects.all()
class IpTypeForm(ModelForm): class IpTypeForm(FormRevMixin, ModelForm):
"""Formulaire d'ajout d'un iptype. Pas d'edition de l'ip de start et de """Formulaire d'ajout d'un iptype. Pas d'edition de l'ip de start et de
stop après creation""" stop après creation"""
class Meta: class Meta:
@ -226,7 +227,7 @@ class EditIpTypeForm(IpTypeForm):
'ouverture_ports'] 'ouverture_ports']
class DelIpTypeForm(Form): class DelIpTypeForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs iptype""" """Suppression d'un ou plusieurs iptype"""
iptypes = forms.ModelMultipleChoiceField( iptypes = forms.ModelMultipleChoiceField(
queryset=IpType.objects.none(), queryset=IpType.objects.none(),
@ -243,7 +244,7 @@ class DelIpTypeForm(Form):
self.fields['iptypes'].queryset = IpType.objects.all() self.fields['iptypes'].queryset = IpType.objects.all()
class ExtensionForm(ModelForm): class ExtensionForm(FormRevMixin, ModelForm):
"""Formulaire d'ajout et edition d'une extension""" """Formulaire d'ajout et edition d'une extension"""
class Meta: class Meta:
model = Extension model = Extension
@ -258,7 +259,7 @@ class ExtensionForm(ModelForm):
self.fields['soa'].label = 'En-tête SOA à utiliser' self.fields['soa'].label = 'En-tête SOA à utiliser'
class DelExtensionForm(Form): class DelExtensionForm(FormRevMixin, Form):
"""Suppression d'une ou plusieurs extensions""" """Suppression d'une ou plusieurs extensions"""
extensions = forms.ModelMultipleChoiceField( extensions = forms.ModelMultipleChoiceField(
queryset=Extension.objects.none(), queryset=Extension.objects.none(),
@ -275,7 +276,7 @@ class DelExtensionForm(Form):
self.fields['extensions'].queryset = Extension.objects.all() self.fields['extensions'].queryset = Extension.objects.all()
class Ipv6ListForm(FieldPermissionFormMixin, ModelForm): class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Gestion des ipv6 d'une machine""" """Gestion des ipv6 d'une machine"""
class Meta: class Meta:
model = Ipv6List model = Ipv6List
@ -286,7 +287,7 @@ class Ipv6ListForm(FieldPermissionFormMixin, ModelForm):
super(Ipv6ListForm, self).__init__(*args, prefix=prefix, **kwargs) super(Ipv6ListForm, self).__init__(*args, prefix=prefix, **kwargs)
class SOAForm(ModelForm): class SOAForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un SOA""" """Ajout et edition d'un SOA"""
class Meta: class Meta:
model = SOA model = SOA
@ -297,7 +298,7 @@ class SOAForm(ModelForm):
super(SOAForm, self).__init__(*args, prefix=prefix, **kwargs) super(SOAForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelSOAForm(Form): class DelSOAForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs SOA""" """Suppression d'un ou plusieurs SOA"""
soa = forms.ModelMultipleChoiceField( soa = forms.ModelMultipleChoiceField(
queryset=SOA.objects.none(), queryset=SOA.objects.none(),
@ -314,7 +315,7 @@ class DelSOAForm(Form):
self.fields['soa'].queryset = SOA.objects.all() self.fields['soa'].queryset = SOA.objects.all()
class MxForm(ModelForm): class MxForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un MX""" """Ajout et edition d'un MX"""
class Meta: class Meta:
model = Mx model = Mx
@ -327,7 +328,7 @@ class MxForm(ModelForm):
interface_parent=None interface_parent=None
).select_related('extension') ).select_related('extension')
class DelMxForm(Form): class DelMxForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs MX""" """Suppression d'un ou plusieurs MX"""
mx = forms.ModelMultipleChoiceField( mx = forms.ModelMultipleChoiceField(
queryset=Mx.objects.none(), queryset=Mx.objects.none(),
@ -344,7 +345,7 @@ class DelMxForm(Form):
self.fields['mx'].queryset = Mx.objects.all() self.fields['mx'].queryset = Mx.objects.all()
class NsForm(ModelForm): class NsForm(FormRevMixin, ModelForm):
"""Ajout d'un NS pour une zone """Ajout d'un NS pour une zone
On exclue les CNAME dans les objets domain (interdit par la rfc) On exclue les CNAME dans les objets domain (interdit par la rfc)
donc on prend uniquemet """ donc on prend uniquemet """
@ -360,7 +361,7 @@ class NsForm(ModelForm):
).select_related('extension') ).select_related('extension')
class DelNsForm(Form): class DelNsForm(FormRevMixin, Form):
"""Suppresion d'un ou plusieurs NS""" """Suppresion d'un ou plusieurs NS"""
ns = forms.ModelMultipleChoiceField( ns = forms.ModelMultipleChoiceField(
queryset=Ns.objects.none(), queryset=Ns.objects.none(),
@ -377,7 +378,7 @@ class DelNsForm(Form):
self.fields['ns'].queryset = Ns.objects.all() self.fields['ns'].queryset = Ns.objects.all()
class TxtForm(ModelForm): class TxtForm(FormRevMixin, ModelForm):
"""Ajout d'un txt pour une zone""" """Ajout d'un txt pour une zone"""
class Meta: class Meta:
model = Txt model = Txt
@ -388,7 +389,7 @@ class TxtForm(ModelForm):
super(TxtForm, self).__init__(*args, prefix=prefix, **kwargs) super(TxtForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelTxtForm(Form): class DelTxtForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs TXT""" """Suppression d'un ou plusieurs TXT"""
txt = forms.ModelMultipleChoiceField( txt = forms.ModelMultipleChoiceField(
queryset=Txt.objects.none(), queryset=Txt.objects.none(),
@ -405,7 +406,7 @@ class DelTxtForm(Form):
self.fields['txt'].queryset = Txt.objects.all() self.fields['txt'].queryset = Txt.objects.all()
class SrvForm(ModelForm): class SrvForm(FormRevMixin, ModelForm):
"""Ajout d'un srv pour une zone""" """Ajout d'un srv pour une zone"""
class Meta: class Meta:
model = Srv model = Srv
@ -416,7 +417,7 @@ class SrvForm(ModelForm):
super(SrvForm, self).__init__(*args, prefix=prefix, **kwargs) super(SrvForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelSrvForm(Form): class DelSrvForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs Srv""" """Suppression d'un ou plusieurs Srv"""
srv = forms.ModelMultipleChoiceField( srv = forms.ModelMultipleChoiceField(
queryset=Srv.objects.none(), queryset=Srv.objects.none(),
@ -433,7 +434,7 @@ class DelSrvForm(Form):
self.fields['srv'].queryset = Srv.objects.all() self.fields['srv'].queryset = Srv.objects.all()
class NasForm(ModelForm): class NasForm(FormRevMixin, ModelForm):
"""Ajout d'un type de nas (machine d'authentification, """Ajout d'un type de nas (machine d'authentification,
swicths, bornes...)""" swicths, bornes...)"""
class Meta: class Meta:
@ -445,7 +446,7 @@ class NasForm(ModelForm):
super(NasForm, self).__init__(*args, prefix=prefix, **kwargs) super(NasForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelNasForm(Form): class DelNasForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs nas""" """Suppression d'un ou plusieurs nas"""
nas = forms.ModelMultipleChoiceField( nas = forms.ModelMultipleChoiceField(
queryset=Nas.objects.none(), queryset=Nas.objects.none(),
@ -462,7 +463,7 @@ class DelNasForm(Form):
self.fields['nas'].queryset = Nas.objects.all() self.fields['nas'].queryset = Nas.objects.all()
class ServiceForm(ModelForm): class ServiceForm(FormRevMixin, ModelForm):
"""Ajout et edition d'une classe de service : dns, dhcp, etc""" """Ajout et edition d'une classe de service : dns, dhcp, etc"""
class Meta: class Meta:
model = Service model = Service
@ -482,7 +483,7 @@ class ServiceForm(ModelForm):
return instance return instance
class DelServiceForm(Form): class DelServiceForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs service""" """Suppression d'un ou plusieurs service"""
service = forms.ModelMultipleChoiceField( service = forms.ModelMultipleChoiceField(
queryset=Service.objects.none(), queryset=Service.objects.none(),
@ -499,7 +500,7 @@ class DelServiceForm(Form):
self.fields['service'].queryset = Service.objects.all() self.fields['service'].queryset = Service.objects.all()
class VlanForm(ModelForm): class VlanForm(FormRevMixin, ModelForm):
"""Ajout d'un vlan : id, nom""" """Ajout d'un vlan : id, nom"""
class Meta: class Meta:
model = Vlan model = Vlan
@ -510,7 +511,7 @@ class VlanForm(ModelForm):
super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs) super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelVlanForm(Form): class DelVlanForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs vlans""" """Suppression d'un ou plusieurs vlans"""
vlan = forms.ModelMultipleChoiceField( vlan = forms.ModelMultipleChoiceField(
queryset=Vlan.objects.none(), queryset=Vlan.objects.none(),
@ -527,7 +528,7 @@ class DelVlanForm(Form):
self.fields['vlan'].queryset = Vlan.objects.all() self.fields['vlan'].queryset = Vlan.objects.all()
class EditOuverturePortConfigForm(ModelForm): class EditOuverturePortConfigForm(FormRevMixin, ModelForm):
"""Edition de la liste des profils d'ouverture de ports """Edition de la liste des profils d'ouverture de ports
pour l'interface""" pour l'interface"""
class Meta: class Meta:
@ -543,7 +544,7 @@ class EditOuverturePortConfigForm(ModelForm):
) )
class EditOuverturePortListForm(ModelForm): class EditOuverturePortListForm(FormRevMixin, ModelForm):
"""Edition de la liste des ports et profils d'ouverture """Edition de la liste des ports et profils d'ouverture
des ports""" des ports"""
class Meta: class Meta:

View file

@ -27,6 +27,7 @@ from datetime import timedelta
import re import re
from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress
from ipaddress import IPv6Address from ipaddress import IPv6Address
from itertools import chain
from django.db import models from django.db import models
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_save, post_delete
@ -39,13 +40,13 @@ from django.core.validators import MaxValueValidator
from macaddress.fields import MACAddressField from macaddress.fields import MACAddressField
from re2o.field_permissions import FieldPermissionModelMixin from re2o.field_permissions import FieldPermissionModelMixin
from re2o.mixins import AclMixin from re2o.mixins import AclMixin, RevMixin
import users.models import users.models
import preferences.models import preferences.models
class Machine(FieldPermissionModelMixin, models.Model): class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
""" Class définissant une machine, object parent user, objets fils """ Class définissant une machine, object parent user, objets fils
interfaces""" interfaces"""
PRETTY_NAME = "Machine" PRETTY_NAME = "Machine"
@ -72,6 +73,11 @@ class Machine(FieldPermissionModelMixin, models.Model):
""" """
return Machine.objects.get(pk=machineid) return Machine.objects.get(pk=machineid)
def linked_objects(self):
"""Return linked objects : machine and domain.
Usefull in history display"""
return chain(self.interface_set.all(), Domain.objects.filter(interface_parent__in=self.interface_set.all()))
@staticmethod @staticmethod
def can_change_user(user_request, *args, **kwargs): def can_change_user(user_request, *args, **kwargs):
"""Checks if an user is allowed to change the user who owns a """Checks if an user is allowed to change the user who owns a
@ -163,7 +169,7 @@ class Machine(FieldPermissionModelMixin, models.Model):
return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name) return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name)
class MachineType(AclMixin, models.Model): class MachineType(RevMixin, AclMixin, models.Model):
""" Type de machine, relié à un type d'ip, affecté aux interfaces""" """ Type de machine, relié à un type d'ip, affecté aux interfaces"""
PRETTY_NAME = "Type de machine" PRETTY_NAME = "Type de machine"
@ -203,7 +209,7 @@ class MachineType(AclMixin, models.Model):
return self.type return self.type
class IpType(AclMixin, models.Model): class IpType(RevMixin, AclMixin, models.Model):
""" Type d'ip, définissant un range d'ip, affecté aux machine types""" """ Type d'ip, définissant un range d'ip, affecté aux machine types"""
PRETTY_NAME = "Type d'ip" PRETTY_NAME = "Type d'ip"
@ -333,7 +339,7 @@ class IpType(AclMixin, models.Model):
return self.type return self.type
class Vlan(AclMixin, models.Model): class Vlan(RevMixin, AclMixin, models.Model):
""" Un vlan : vlan_id et nom """ Un vlan : vlan_id et nom
On limite le vlan id entre 0 et 4096, comme défini par la norme""" On limite le vlan id entre 0 et 4096, comme défini par la norme"""
PRETTY_NAME = "Vlans" PRETTY_NAME = "Vlans"
@ -351,7 +357,7 @@ class Vlan(AclMixin, models.Model):
return self.name return self.name
class Nas(AclMixin, models.Model): class Nas(RevMixin, AclMixin, models.Model):
""" Les nas. Associé à un machine_type. """ Les nas. Associé à un machine_type.
Permet aussi de régler le port_access_mode (802.1X ou mac-address) pour Permet aussi de régler le port_access_mode (802.1X ou mac-address) pour
le radius. Champ autocapture de la mac à true ou false""" le radius. Champ autocapture de la mac à true ou false"""
@ -390,7 +396,7 @@ class Nas(AclMixin, models.Model):
return self.name return self.name
class SOA(AclMixin, models.Model): class SOA(RevMixin, AclMixin, models.Model):
""" """
Un enregistrement SOA associé à une extension Un enregistrement SOA associé à une extension
Les valeurs par défault viennent des recommandations RIPE : Les valeurs par défault viennent des recommandations RIPE :
@ -467,7 +473,7 @@ class SOA(AclMixin, models.Model):
class Extension(AclMixin, models.Model): class Extension(RevMixin, AclMixin, models.Model):
""" Extension dns type example.org. Précise si tout le monde peut """ Extension dns type example.org. Précise si tout le monde peut
l'utiliser, associé à un origin (ip d'origine)""" l'utiliser, associé à un origin (ip d'origine)"""
PRETTY_NAME = "Extensions dns" PRETTY_NAME = "Extensions dns"
@ -530,7 +536,7 @@ class Extension(AclMixin, models.Model):
super(Extension, self).clean(*args, **kwargs) super(Extension, self).clean(*args, **kwargs)
class Mx(AclMixin, models.Model): class Mx(RevMixin, AclMixin, models.Model):
""" Entrées des MX. Enregistre la zone (extension) associée et la """ Entrées des MX. Enregistre la zone (extension) associée et la
priorité priorité
Todo : pouvoir associer un MX à une interface """ Todo : pouvoir associer un MX à une interface """
@ -555,7 +561,7 @@ class Mx(AclMixin, models.Model):
return str(self.zone) + ' ' + str(self.priority) + ' ' + str(self.name) return str(self.zone) + ' ' + str(self.priority) + ' ' + str(self.name)
class Ns(AclMixin, models.Model): class Ns(RevMixin, AclMixin, models.Model):
"""Liste des enregistrements name servers par zone considéérée""" """Liste des enregistrements name servers par zone considéérée"""
PRETTY_NAME = "Enregistrements NS" PRETTY_NAME = "Enregistrements NS"
@ -576,7 +582,7 @@ class Ns(AclMixin, models.Model):
return str(self.zone) + ' ' + str(self.ns) return str(self.zone) + ' ' + str(self.ns)
class Txt(AclMixin, models.Model): class Txt(RevMixin, AclMixin, models.Model):
""" Un enregistrement TXT associé à une extension""" """ Un enregistrement TXT associé à une extension"""
PRETTY_NAME = "Enregistrement TXT" PRETTY_NAME = "Enregistrement TXT"
@ -599,7 +605,7 @@ class Txt(AclMixin, models.Model):
return str(self.field1).ljust(15) + " IN TXT " + str(self.field2) return str(self.field1).ljust(15) + " IN TXT " + str(self.field2)
class Srv(AclMixin, models.Model): class Srv(RevMixin, AclMixin, models.Model):
PRETTY_NAME = "Enregistrement Srv" PRETTY_NAME = "Enregistrement Srv"
TCP = 'TCP' TCP = 'TCP'
@ -661,7 +667,7 @@ class Srv(AclMixin, models.Model):
str(self.port) + ' ' + str(self.target) + '.' str(self.port) + ' ' + str(self.target) + '.'
class Interface(AclMixin, FieldPermissionModelMixin,models.Model): class Interface(RevMixin, AclMixin, FieldPermissionModelMixin,models.Model):
""" Une interface. Objet clef de l'application machine : """ Une interface. Objet clef de l'application machine :
- une address mac unique. Possibilité de la rendre unique avec le - une address mac unique. Possibilité de la rendre unique avec le
typemachine typemachine
@ -908,7 +914,7 @@ class Interface(AclMixin, FieldPermissionModelMixin,models.Model):
return self.ipv4 and not self.has_private_ip() return self.ipv4 and not self.has_private_ip()
class Ipv6List(AclMixin, FieldPermissionModelMixin, models.Model): class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
PRETTY_NAME = 'Enregistrements Ipv6 des machines' PRETTY_NAME = 'Enregistrements Ipv6 des machines'
ipv6 = models.GenericIPAddressField( ipv6 = models.GenericIPAddressField(
@ -1012,7 +1018,7 @@ class Ipv6List(AclMixin, FieldPermissionModelMixin, models.Model):
return str(self.ipv6) return str(self.ipv6)
class Domain(AclMixin, models.Model): class Domain(RevMixin, AclMixin, models.Model):
""" Objet domain. Enregistrement A et CNAME en même temps : permet de """ Objet domain. Enregistrement A et CNAME en même temps : permet de
stocker les alias et les nom de machines, suivant si interface_parent stocker les alias et les nom de machines, suivant si interface_parent
ou cname sont remplis""" ou cname sont remplis"""
@ -1170,7 +1176,7 @@ class Domain(AclMixin, models.Model):
return str(self.name) + str(self.extension) return str(self.name) + str(self.extension)
class IpList(AclMixin, models.Model): class IpList(RevMixin, AclMixin, models.Model):
PRETTY_NAME = "Addresses ipv4" PRETTY_NAME = "Addresses ipv4"
ipv4 = models.GenericIPAddressField(protocol='IPv4', unique=True) ipv4 = models.GenericIPAddressField(protocol='IPv4', unique=True)
@ -1202,7 +1208,7 @@ class IpList(AclMixin, models.Model):
return self.ipv4 return self.ipv4
class Service(AclMixin, models.Model): class Service(RevMixin, AclMixin, models.Model):
""" Definition d'un service (dhcp, dns, etc)""" """ Definition d'un service (dhcp, dns, etc)"""
PRETTY_NAME = "Services à générer (dhcp, dns, etc)" PRETTY_NAME = "Services à générer (dhcp, dns, etc)"
@ -1256,7 +1262,7 @@ def regen(service):
return return
class Service_link(AclMixin, models.Model): class Service_link(RevMixin, AclMixin, models.Model):
""" Definition du lien entre serveurs et services""" """ Definition du lien entre serveurs et services"""
PRETTY_NAME = "Relation entre service et serveur" PRETTY_NAME = "Relation entre service et serveur"
@ -1287,7 +1293,7 @@ class Service_link(AclMixin, models.Model):
return str(self.server) + " " + str(self.service) return str(self.server) + " " + str(self.service)
class OuverturePortList(AclMixin, models.Model): class OuverturePortList(RevMixin, AclMixin, models.Model):
"""Liste des ports ouverts sur une interface.""" """Liste des ports ouverts sur une interface."""
PRETTY_NAME = "Profil d'ouverture de ports" PRETTY_NAME = "Profil d'ouverture de ports"
@ -1346,7 +1352,7 @@ class OuverturePortList(AclMixin, models.Model):
) )
class OuverturePort(AclMixin, models.Model): class OuverturePort(RevMixin, AclMixin, models.Model):
""" """
Représente un simple port ou une plage de ports. Représente un simple port ou une plage de ports.

View file

@ -38,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% can_edit alias %} {% can_edit alias %}
{% include 'buttons/edit.html' with href='machines:edit-alias' id=alias.id %} {% include 'buttons/edit.html' with href='machines:edit-alias' id=alias.id %}
{% acl_end %} {% acl_end %}
{% include 'buttons/history.html' with href='machines:history' name='alias' id=alias.id %} {% include 'buttons/history.html' with href='machines:history' name='domain' id=alias.id %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -39,7 +39,6 @@ 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, F from django.db.models import ProtectedError, F
from django.forms import ValidationError, modelformset_factory from django.forms import ValidationError, modelformset_factory
from django.db import transaction
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
@ -238,20 +237,11 @@ def new_machine(request, user, userid):
domain.instance.interface_parent = new_interface domain.instance.interface_parent = new_interface
if domain.is_valid(): if domain.is_valid():
new_domain = domain.save(commit=False) new_domain = domain.save(commit=False)
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
with transaction.atomic(), reversion.create_revision(): new_interface.save()
new_interface.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_domain.interface_parent = new_interface new_domain.interface_parent = new_interface
with transaction.atomic(), reversion.create_revision(): new_domain.save()
new_domain.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(reverse( return redirect(reverse(
'users:profil', 'users:profil',
@ -287,18 +277,12 @@ def edit_interface(request, interface_instance, interfaceid):
new_machine = machine_form.save(commit=False) new_machine = machine_form.save(commit=False)
new_interface = interface_form.save(commit=False) new_interface = interface_form.save(commit=False)
new_domain = domain_form.save(commit=False) new_domain = domain_form.save(commit=False)
with transaction.atomic(), reversion.create_revision(): if machine_form.changed_data:
new_machine.save() new_machine.save()
reversion.set_user(request.user) if interface_form.changed_data:
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) if domain_form.changed_data:
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in interface_form.changed_data))
with transaction.atomic(), reversion.create_revision():
new_domain.save() new_domain.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in domain_form.changed_data))
messages.success(request, "La machine a été modifiée") messages.success(request, "La machine a été modifiée")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
@ -318,9 +302,7 @@ def edit_interface(request, interface_instance, interfaceid):
def del_machine(request, machine, machineid): def del_machine(request, machine, machineid):
""" Supprime une machine, interfaces en mode cascade""" """ Supprime une machine, interfaces en mode cascade"""
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(reverse( return redirect(reverse(
'users:profil', 'users:profil',
@ -342,15 +324,9 @@ def new_interface(request, machine, machineid):
new_interface.machine = machine new_interface.machine = machine
if domain_form.is_valid(): if domain_form.is_valid():
new_domain = domain_form.save(commit=False) new_domain = domain_form.save(commit=False)
with transaction.atomic(), reversion.create_revision(): new_interface.save()
new_interface.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_domain.interface_parent = new_interface new_domain.interface_parent = new_interface
with transaction.atomic(), reversion.create_revision(): new_domain.save()
new_domain.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(reverse( return redirect(reverse(
'users:profil', 'users:profil',
@ -370,11 +346,9 @@ def del_interface(request, interface, interfaceid):
""" Supprime une interface. Domain objet en mode cascade""" """ Supprime une interface. Domain objet en mode cascade"""
if request.method == "POST": if request.method == "POST":
machine = interface.machine machine = interface.machine
with transaction.atomic(), reversion.create_revision(): interface.delete()
interface.delete() if not machine.interface_set.all():
if not machine.interface_set.all(): machine.delete()
machine.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(reverse( return redirect(reverse(
'users:profil', 'users:profil',
@ -390,10 +364,7 @@ def new_ipv6list(request, interface, interfaceid):
ipv6list_instance = Ipv6List(interface=interface) ipv6list_instance = Ipv6List(interface=interface)
ipv6 = Ipv6ListForm(request.POST or None, instance=ipv6list_instance, user=request.user) ipv6 = Ipv6ListForm(request.POST or None, instance=ipv6list_instance, user=request.user)
if ipv6.is_valid(): if ipv6.is_valid():
with transaction.atomic(), reversion.create_revision(): ipv6.save()
ipv6.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Ipv6 ajoutée") messages.success(request, "Ipv6 ajoutée")
return redirect(reverse( return redirect(reverse(
'machines:index-ipv6', 'machines:index-ipv6',
@ -407,11 +378,9 @@ def edit_ipv6list(request, ipv6list_instance, ipv6listid):
"""Edition d'une ipv6""" """Edition d'une ipv6"""
ipv6 = Ipv6ListForm(request.POST or None, instance=ipv6list_instance, user=request.user) ipv6 = Ipv6ListForm(request.POST or None, instance=ipv6list_instance, user=request.user)
if ipv6.is_valid(): if ipv6.is_valid():
with transaction.atomic(), reversion.create_revision(): if ipv6.changed_data:
ipv6.save() ipv6.save()
reversion.set_user(request.user) messages.success(request, "Ipv6 modifiée")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in ipv6.changed_data))
messages.success(request, "Ipv6 modifiée")
return redirect(reverse( return redirect(reverse(
'machines:index-ipv6', 'machines:index-ipv6',
kwargs={'interfaceid':str(ipv6list_instance.interface.id)} kwargs={'interfaceid':str(ipv6list_instance.interface.id)}
@ -424,9 +393,7 @@ def del_ipv6list(request, ipv6list, ipv6listid):
""" Supprime une ipv6""" """ Supprime une ipv6"""
if request.method == "POST": if request.method == "POST":
interfaceid = ipv6list.interface.id interfaceid = ipv6list.interface.id
with transaction.atomic(), reversion.create_revision(): ipv6list.delete()
ipv6list.delete()
reversion.set_user(request.user)
messages.success(request, "L'ipv6 a été détruite") messages.success(request, "L'ipv6 a été détruite")
return redirect(reverse( return redirect(reverse(
'machines:index-ipv6', 'machines:index-ipv6',
@ -441,10 +408,7 @@ def add_iptype(request):
iptype = IpTypeForm(request.POST or None) iptype = IpTypeForm(request.POST or None)
if iptype.is_valid(): if iptype.is_valid():
with transaction.atomic(), reversion.create_revision(): iptype.save()
iptype.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Ce type d'ip a été ajouté") messages.success(request, "Ce type d'ip a été ajouté")
return redirect(reverse('machines:index-iptype')) return redirect(reverse('machines:index-iptype'))
return form({'iptypeform': iptype, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'iptypeform': iptype, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -456,11 +420,9 @@ def edit_iptype(request, iptype_instance, iptypeid):
iptype = EditIpTypeForm(request.POST or None, instance=iptype_instance) iptype = EditIpTypeForm(request.POST or None, instance=iptype_instance)
if iptype.is_valid(): if iptype.is_valid():
with transaction.atomic(), reversion.create_revision(): if iptype.changed_data:
iptype.save() iptype.save()
reversion.set_user(request.user) messages.success(request, "Type d'ip modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in iptype.changed_data))
messages.success(request, "Type d'ip modifié")
return redirect(reverse('machines:index-iptype')) return redirect(reverse('machines:index-iptype'))
return form({'iptypeform': iptype, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'iptypeform': iptype, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -473,9 +435,7 @@ def del_iptype(request, instances):
iptype_dels = iptype.cleaned_data['iptypes'] iptype_dels = iptype.cleaned_data['iptypes']
for iptype_del in iptype_dels: for iptype_del in iptype_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): iptype_del.delete()
iptype_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le type d'ip a été supprimé") messages.success(request, "Le type d'ip a été supprimé")
except ProtectedError: except ProtectedError:
messages.error(request, "Le type d'ip %s est affectée à au moins une machine, vous ne pouvez pas le supprimer" % iptype_del) messages.error(request, "Le type d'ip %s est affectée à au moins une machine, vous ne pouvez pas le supprimer" % iptype_del)
@ -488,10 +448,7 @@ 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(reverse('machines:index-machinetype')) return redirect(reverse('machines:index-machinetype'))
return form({'machinetypeform': machinetype, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'machinetypeform': machinetype, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -499,14 +456,11 @@ def add_machinetype(request):
@login_required @login_required
@can_edit(MachineType) @can_edit(MachineType)
def edit_machinetype(request, machinetype_instance, machinetypeid): def edit_machinetype(request, machinetype_instance, machinetypeid):
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(): if machinetype.changed_data:
machinetype.save() machinetype.save()
reversion.set_user(request.user) messages.success(request, "Type de machine modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in machinetype.changed_data))
messages.success(request, "Type de machine modifié")
return redirect(reverse('machines:index-machinetype')) return redirect(reverse('machines:index-machinetype'))
return form({'machinetypeform': machinetype, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'machinetypeform': machinetype, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -518,9 +472,7 @@ def del_machinetype(request, instances):
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)
@ -530,13 +482,9 @@ def del_machinetype(request, instances):
@login_required @login_required
@can_create(Extension) @can_create(Extension)
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(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'extensionform': extension, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'extensionform': extension, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -544,14 +492,11 @@ def add_extension(request):
@login_required @login_required
@can_edit(Extension) @can_edit(Extension)
def edit_extension(request, extension_instance, extensionid): def edit_extension(request, extension_instance, extensionid):
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(): if extension.changed_data:
extension.save() extension.save()
reversion.set_user(request.user) messages.success(request, "Extension modifiée")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in extension.changed_data))
messages.success(request, "Extension modifiée")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'extensionform': extension, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'extensionform': extension, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -563,9 +508,7 @@ def del_extension(request, instances):
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)
@ -575,13 +518,9 @@ def del_extension(request, instances):
@login_required @login_required
@can_create(SOA) @can_create(SOA)
def add_soa(request): def add_soa(request):
soa = SOAForm(request.POST or None) soa = SOAForm(request.POST or None)
if soa.is_valid(): if soa.is_valid():
with transaction.atomic(), reversion.create_revision(): soa.save()
soa.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement SOA a été ajouté") messages.success(request, "Cet enregistrement SOA a été ajouté")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'soaform': soa, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'soaform': soa, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -589,14 +528,11 @@ def add_soa(request):
@login_required @login_required
@can_edit(SOA) @can_edit(SOA)
def edit_soa(request, soa_instance, soaid): def edit_soa(request, soa_instance, soaid):
soa = SOAForm(request.POST or None, instance=soa_instance) soa = SOAForm(request.POST or None, instance=soa_instance)
if soa.is_valid(): if soa.is_valid():
with transaction.atomic(), reversion.create_revision(): if soa.changed_data:
soa.save() soa.save()
reversion.set_user(request.user) messages.success(request, "SOA modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in soa.changed_data))
messages.success(request, "SOA modifié")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'soaform': soa, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'soaform': soa, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -608,9 +544,7 @@ def del_soa(request, instances):
soa_dels = soa.cleaned_data['soa'] soa_dels = soa.cleaned_data['soa']
for soa_del in soa_dels: for soa_del in soa_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): soa_del.delete()
soa_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le SOA a été supprimée") messages.success(request, "Le SOA a été supprimée")
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur le SOA suivant %s ne peut être supprimé" % soa_del) messages.error(request, "Erreur le SOA suivant %s ne peut être supprimé" % soa_del)
@ -620,13 +554,9 @@ def del_soa(request, instances):
@login_required @login_required
@can_create(Mx) @can_create(Mx)
def add_mx(request): def add_mx(request):
mx = MxForm(request.POST or None) mx = MxForm(request.POST or None)
if mx.is_valid(): if mx.is_valid():
with transaction.atomic(), reversion.create_revision(): mx.save()
mx.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement mx a été ajouté") messages.success(request, "Cet enregistrement mx a été ajouté")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'mxform': mx, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'mxform': mx, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -634,14 +564,11 @@ def add_mx(request):
@login_required @login_required
@can_edit(Mx) @can_edit(Mx)
def edit_mx(request, mx_instance, mxid): def edit_mx(request, mx_instance, mxid):
mx = MxForm(request.POST or None, instance=mx_instance) mx = MxForm(request.POST or None, instance=mx_instance)
if mx.is_valid(): if mx.is_valid():
with transaction.atomic(), reversion.create_revision(): if mx.changed_data:
mx.save() mx.save()
reversion.set_user(request.user) messages.success(request, "Mx modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in mx.changed_data))
messages.success(request, "Mx modifié")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'mxform': mx, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'mxform': mx, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -653,9 +580,7 @@ def del_mx(request, instances):
mx_dels = mx.cleaned_data['mx'] mx_dels = mx.cleaned_data['mx']
for mx_del in mx_dels: for mx_del in mx_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): mx_del.delete()
mx_del.delete()
reversion.set_user(request.user)
messages.success(request, "L'mx a été supprimée") messages.success(request, "L'mx a été supprimée")
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur le Mx suivant %s ne peut être supprimé" % mx_del) messages.error(request, "Erreur le Mx suivant %s ne peut être supprimé" % mx_del)
@ -665,13 +590,9 @@ def del_mx(request, instances):
@login_required @login_required
@can_create(Ns) @can_create(Ns)
def add_ns(request): def add_ns(request):
ns = NsForm(request.POST or None) ns = NsForm(request.POST or None)
if ns.is_valid(): if ns.is_valid():
with transaction.atomic(), reversion.create_revision(): ns.save()
ns.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement ns a été ajouté") messages.success(request, "Cet enregistrement ns a été ajouté")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'nsform': ns, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'nsform': ns, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -679,14 +600,11 @@ def add_ns(request):
@login_required @login_required
@can_edit(Ns) @can_edit(Ns)
def edit_ns(request, ns_instance, nsid): def edit_ns(request, ns_instance, nsid):
ns = NsForm(request.POST or None, instance=ns_instance) ns = NsForm(request.POST or None, instance=ns_instance)
if ns.is_valid(): if ns.is_valid():
with transaction.atomic(), reversion.create_revision(): if ns.changed_data:
ns.save() ns.save()
reversion.set_user(request.user) messages.success(request, "Ns modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in ns.changed_data))
messages.success(request, "Ns modifié")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'nsform': ns, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'nsform': ns, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -698,9 +616,7 @@ def del_ns(request, instances):
ns_dels = ns.cleaned_data['ns'] ns_dels = ns.cleaned_data['ns']
for ns_del in ns_dels: for ns_del in ns_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): ns_del.delete()
ns_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le ns a été supprimée") messages.success(request, "Le ns a été supprimée")
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur le Ns suivant %s ne peut être supprimé" % ns_del) messages.error(request, "Erreur le Ns suivant %s ne peut être supprimé" % ns_del)
@ -710,13 +626,9 @@ def del_ns(request, instances):
@login_required @login_required
@can_create(Txt) @can_create(Txt)
def add_txt(request): def add_txt(request):
txt = TxtForm(request.POST or None) txt = TxtForm(request.POST or None)
if txt.is_valid(): if txt.is_valid():
with transaction.atomic(), reversion.create_revision(): txt.save()
txt.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement text a été ajouté") messages.success(request, "Cet enregistrement text a été ajouté")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'txtform': txt, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'txtform': txt, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -724,14 +636,11 @@ def add_txt(request):
@login_required @login_required
@can_edit(Txt) @can_edit(Txt)
def edit_txt(request, txt_instance, txtid): def edit_txt(request, txt_instance, txtid):
txt = TxtForm(request.POST or None, instance=txt_instance) txt = TxtForm(request.POST or None, instance=txt_instance)
if txt.is_valid(): if txt.is_valid():
with transaction.atomic(), reversion.create_revision(): if txt.changed_data:
txt.save() txt.save()
reversion.set_user(request.user) messages.success(request, "Txt modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in txt.changed_data))
messages.success(request, "Txt modifié")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'txtform': txt, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'txtform': txt, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -743,9 +652,7 @@ def del_txt(request, instances):
txt_dels = txt.cleaned_data['txt'] txt_dels = txt.cleaned_data['txt']
for txt_del in txt_dels: for txt_del in txt_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): txt_del.delete()
txt_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le txt a été supprimé") messages.success(request, "Le txt a été supprimé")
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur le Txt suivant %s ne peut être supprimé" % txt_del) messages.error(request, "Erreur le Txt suivant %s ne peut être supprimé" % txt_del)
@ -755,13 +662,9 @@ def del_txt(request, instances):
@login_required @login_required
@can_create(Srv) @can_create(Srv)
def add_srv(request): def add_srv(request):
srv = SrvForm(request.POST or None) srv = SrvForm(request.POST or None)
if srv.is_valid(): if srv.is_valid():
with transaction.atomic(), reversion.create_revision(): srv.save()
srv.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement srv a été ajouté") messages.success(request, "Cet enregistrement srv a été ajouté")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'srvform': srv, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'srvform': srv, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -769,14 +672,11 @@ def add_srv(request):
@login_required @login_required
@can_edit(Srv) @can_edit(Srv)
def edit_srv(request, srv_instance, srvid): def edit_srv(request, srv_instance, srvid):
srv = SrvForm(request.POST or None, instance=srv_instance) srv = SrvForm(request.POST or None, instance=srv_instance)
if srv.is_valid(): if srv.is_valid():
with transaction.atomic(), reversion.create_revision(): if srv.changed_data:
srv.save() srv.save()
reversion.set_user(request.user) messages.success(request, "Srv modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in srv.changed_data))
messages.success(request, "Srv modifié")
return redirect(reverse('machines:index-extension')) return redirect(reverse('machines:index-extension'))
return form({'srvform': srv, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'srvform': srv, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -788,9 +688,7 @@ def del_srv(request, instances):
srv_dels = srv.cleaned_data['srv'] srv_dels = srv.cleaned_data['srv']
for srv_del in srv_dels: for srv_del in srv_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): srv_del.delete()
srv_del.delete()
reversion.set_user(request.user)
messages.success(request, "L'srv a été supprimée") messages.success(request, "L'srv a été supprimée")
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur le Srv suivant %s ne peut être supprimé" % srv_del) messages.error(request, "Erreur le Srv suivant %s ne peut être supprimé" % srv_del)
@ -801,15 +699,11 @@ def del_srv(request, instances):
@can_create(Domain) @can_create(Domain)
@can_edit(Interface) @can_edit(Interface)
def add_alias(request, interface, interfaceid): def add_alias(request, interface, interfaceid):
alias = AliasForm(request.POST or None, user=request.user) alias = AliasForm(request.POST or None, user=request.user)
if alias.is_valid(): if alias.is_valid():
alias = alias.save(commit=False) alias = alias.save(commit=False)
alias.cname = interface.domain alias.cname = interface.domain
with transaction.atomic(), reversion.create_revision(): alias.save()
alias.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet alias a été ajouté") messages.success(request, "Cet alias a été ajouté")
return redirect(reverse( return redirect(reverse(
'machines:index-alias', 'machines:index-alias',
@ -820,14 +714,11 @@ def add_alias(request, interface, interfaceid):
@login_required @login_required
@can_edit(Domain) @can_edit(Domain)
def edit_alias(request, domain_instance, domainid): def edit_alias(request, domain_instance, domainid):
alias = AliasForm(request.POST or None, instance=domain_instance, user=request.user) alias = AliasForm(request.POST or None, instance=domain_instance, user=request.user)
if alias.is_valid(): if alias.is_valid():
with transaction.atomic(), reversion.create_revision(): if alias.changed_data:
domain_instance = alias.save() domain_instance = alias.save()
reversion.set_user(request.user) messages.success(request, "Alias modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in alias.changed_data))
messages.success(request, "Alias modifié")
return redirect(reverse( return redirect(reverse(
'machines:index-alias', 'machines:index-alias',
kwargs={'interfaceid':str(domain_instance.cname.interface_parent.id)} kwargs={'interfaceid':str(domain_instance.cname.interface_parent.id)}
@ -842,9 +733,7 @@ def del_alias(request, interface, interfaceid):
alias_dels = alias.cleaned_data['alias'] alias_dels = alias.cleaned_data['alias']
for alias_del in alias_dels: for alias_del in alias_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): alias_del.delete()
alias_del.delete()
reversion.set_user(request.user)
messages.success(request, "L'alias %s a été supprimé" % alias_del) messages.success(request, "L'alias %s a été supprimé" % alias_del)
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur l'alias suivant %s ne peut être supprimé" % alias_del) messages.error(request, "Erreur l'alias suivant %s ne peut être supprimé" % alias_del)
@ -858,13 +747,9 @@ def del_alias(request, interface, interfaceid):
@login_required @login_required
@can_create(Service) @can_create(Service)
def add_service(request): def add_service(request):
service = ServiceForm(request.POST or None) service = ServiceForm(request.POST or None)
if service.is_valid(): if service.is_valid():
with transaction.atomic(), reversion.create_revision(): service.save()
service.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement service a été ajouté") messages.success(request, "Cet enregistrement service a été ajouté")
return redirect(reverse('machines:index-service')) return redirect(reverse('machines:index-service'))
return form({'serviceform': service, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'serviceform': service, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -872,14 +757,11 @@ def add_service(request):
@login_required @login_required
@can_edit(Service) @can_edit(Service)
def edit_service(request, service_instance, serviceid): def edit_service(request, service_instance, serviceid):
service = ServiceForm(request.POST or None, instance=service_instance) service = ServiceForm(request.POST or None, instance=service_instance)
if service.is_valid(): if service.is_valid():
with transaction.atomic(), reversion.create_revision(): if service.changed_data:
service.save() service.save()
reversion.set_user(request.user) messages.success(request, "Service modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in service.changed_data))
messages.success(request, "Service modifié")
return redirect(reverse('machines:index-service')) return redirect(reverse('machines:index-service'))
return form({'serviceform': service, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'serviceform': service, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -891,9 +773,7 @@ def del_service(request, instances):
service_dels = service.cleaned_data['service'] service_dels = service.cleaned_data['service']
for service_del in service_dels: for service_del in service_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): service_del.delete()
service_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le service a été supprimée") messages.success(request, "Le service a été supprimée")
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur le service suivant %s ne peut être supprimé" % service_del) messages.error(request, "Erreur le service suivant %s ne peut être supprimé" % service_del)
@ -903,13 +783,9 @@ def del_service(request, instances):
@login_required @login_required
@can_create(Vlan) @can_create(Vlan)
def add_vlan(request): def add_vlan(request):
vlan = VlanForm(request.POST or None) vlan = VlanForm(request.POST or None)
if vlan.is_valid(): if vlan.is_valid():
with transaction.atomic(), reversion.create_revision(): vlan.save()
vlan.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement vlan a été ajouté") messages.success(request, "Cet enregistrement vlan a été ajouté")
return redirect(reverse('machines:index-vlan')) return redirect(reverse('machines:index-vlan'))
return form({'vlanform': vlan, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'vlanform': vlan, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -917,14 +793,11 @@ def add_vlan(request):
@login_required @login_required
@can_edit(Vlan) @can_edit(Vlan)
def edit_vlan(request, vlan_instance, vlanid): def edit_vlan(request, vlan_instance, vlanid):
vlan = VlanForm(request.POST or None, instance=vlan_instance) vlan = VlanForm(request.POST or None, instance=vlan_instance)
if vlan.is_valid(): if vlan.is_valid():
with transaction.atomic(), reversion.create_revision(): if vlan.changed_data:
vlan.save() vlan.save()
reversion.set_user(request.user) messages.success(request, "Vlan modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in vlan.changed_data))
messages.success(request, "Vlan modifié")
return redirect(reverse('machines:index-vlan')) return redirect(reverse('machines:index-vlan'))
return form({'vlanform': vlan, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'vlanform': vlan, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -936,9 +809,7 @@ def del_vlan(request, instances):
vlan_dels = vlan.cleaned_data['vlan'] vlan_dels = vlan.cleaned_data['vlan']
for vlan_del in vlan_dels: for vlan_del in vlan_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): vlan_del.delete()
vlan_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le vlan a été supprimée") messages.success(request, "Le vlan a été supprimée")
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur le Vlan suivant %s ne peut être supprimé" % vlan_del) messages.error(request, "Erreur le Vlan suivant %s ne peut être supprimé" % vlan_del)
@ -948,13 +819,9 @@ def del_vlan(request, instances):
@login_required @login_required
@can_create(Nas) @can_create(Nas)
def add_nas(request): def add_nas(request):
nas = NasForm(request.POST or None) nas = NasForm(request.POST or None)
if nas.is_valid(): if nas.is_valid():
with transaction.atomic(), reversion.create_revision(): nas.save()
nas.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement nas a été ajouté") messages.success(request, "Cet enregistrement nas a été ajouté")
return redirect(reverse('machines:index-nas')) return redirect(reverse('machines:index-nas'))
return form({'nasform': nas, 'action_name' : 'Créer'}, 'machines/machine.html', request) return form({'nasform': nas, 'action_name' : 'Créer'}, 'machines/machine.html', request)
@ -962,14 +829,11 @@ def add_nas(request):
@login_required @login_required
@can_edit(Nas) @can_edit(Nas)
def edit_nas(request, nas_instance, nasid): def edit_nas(request, nas_instance, nasid):
nas = NasForm(request.POST or None, instance=nas_instance) nas = NasForm(request.POST or None, instance=nas_instance)
if nas.is_valid(): if nas.is_valid():
with transaction.atomic(), reversion.create_revision(): if nas.changed_data:
nas.save() nas.save()
reversion.set_user(request.user) messages.success(request, "Nas modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in nas.changed_data))
messages.success(request, "Nas modifié")
return redirect(reverse('machines:index-nas')) return redirect(reverse('machines:index-nas'))
return form({'nasform': nas, 'action_name' : 'Editer'}, 'machines/machine.html', request) return form({'nasform': nas, 'action_name' : 'Editer'}, 'machines/machine.html', request)
@ -981,9 +845,7 @@ def del_nas(request, instances):
nas_dels = nas.cleaned_data['nas'] nas_dels = nas.cleaned_data['nas']
for nas_del in nas_dels: for nas_del in nas_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): nas_del.delete()
nas_del.delete()
reversion.set_user(request.user)
messages.success(request, "Le nas a été supprimé") messages.success(request, "Le nas a été supprimé")
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur le Nas suivant %s ne peut être supprimé" % nas_del) messages.error(request, "Erreur le Nas suivant %s ne peut être supprimé" % nas_del)
@ -1084,7 +946,6 @@ def index_portlist(request):
@login_required @login_required
@can_edit(OuverturePortList) @can_edit(OuverturePortList)
def edit_portlist(request, ouvertureportlist_instance, ouvertureportlistid): def edit_portlist(request, ouvertureportlist_instance, ouvertureportlistid):
port_list = EditOuverturePortListForm(request.POST or None, instance=ouvertureportlist_instance) port_list = EditOuverturePortListForm(request.POST or None, instance=ouvertureportlist_instance)
port_formset = modelformset_factory( port_formset = modelformset_factory(
OuverturePort, OuverturePort,
@ -1095,7 +956,10 @@ def edit_portlist(request, ouvertureportlist_instance, ouvertureportlistid):
validate_min=True, validate_min=True,
)(request.POST or None, queryset=ouvertureportlist_instance.ouvertureport_set.all()) )(request.POST or None, queryset=ouvertureportlist_instance.ouvertureport_set.all())
if port_list.is_valid() and port_formset.is_valid(): if port_list.is_valid() and port_formset.is_valid():
pl = port_list.save() if port_list.changed_data:
pl = port_list.save()
else:
pl = ouvertureportlist_instance
instances = port_formset.save(commit=False) instances = port_formset.save(commit=False)
for to_delete in port_formset.deleted_objects: for to_delete in port_formset.deleted_objects:
to_delete.delete() to_delete.delete()
@ -1116,7 +980,6 @@ def del_portlist(request, port_list_instance, ouvertureportlistid):
@login_required @login_required
@can_create(OuverturePortList) @can_create(OuverturePortList)
def add_portlist(request): def add_portlist(request):
port_list = EditOuverturePortListForm(request.POST or None) port_list = EditOuverturePortListForm(request.POST or None)
port_formset = modelformset_factory( port_formset = modelformset_factory(
OuverturePort, OuverturePort,
@ -1152,8 +1015,9 @@ def configure_ports(request, interface_instance, interfaceid):
messages.error(request, "Attention, l'ipv4 n'est pas publique, l'ouverture n'aura pas d'effet en v4") messages.error(request, "Attention, l'ipv4 n'est pas publique, l'ouverture n'aura pas d'effet en v4")
interface = EditOuverturePortConfigForm(request.POST or None, instance=interface_instance) interface = EditOuverturePortConfigForm(request.POST or None, instance=interface_instance)
if interface.is_valid(): if interface.is_valid():
interface.save() if interface.changed_data:
messages.success(request, "Configuration des ports mise à jour.") interface.save()
messages.success(request, "Configuration des ports mise à jour.")
return redirect(reverse('machines:index')) return redirect(reverse('machines:index'))
return form({'interfaceform' : interface, 'action_name' : 'Editer la configuration'}, 'machines/machine.html', request) return form({'interfaceform' : interface, 'action_name' : 'Editer la configuration'}, 'machines/machine.html', request)

View file

@ -4,6 +4,7 @@
# quelques clics. # quelques clics.
# #
# Copyright © 2018 Gabriel Détraz # Copyright © 2018 Gabriel Détraz
# Copyright © 2017 Charlie Jacomme
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -19,6 +20,29 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from reversion import revisions as reversion
class RevMixin(object):
def save(self, *args, **kwargs):
if self.pk is None:
reversion.set_comment("Création")
return super(RevMixin, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
reversion.set_comment("Suppresion")
return super(RevMixin, self).delete(*args, **kwargs)
class FormRevMixin(object):
def save(self, *args, **kwargs):
if reversion.get_comment() != "" and self.changed_data != []:
reversion.set_comment(reversion.get_comment() + ",%s" % ', '.join(field for field in self.changed_data))
elif self.changed_data:
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in self.changed_data))
return super(FormRevMixin, self).save(*args, **kwargs)
class AclMixin(object): class AclMixin(object):
"""This mixin is used in nearly every class/models defined in re2o apps. """This mixin is used in nearly every class/models defined in re2o apps.
It is used by acl, in models (decorators can_...) and in templates tags It is used by acl, in models (decorators can_...) and in templates tags

View file

@ -89,6 +89,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'reversion.middleware.RevisionMiddleware',
) )
ROOT_URLCONF = 're2o.urls' ROOT_URLCONF = 're2o.urls'

View file

@ -41,7 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<thead> <thead>
<tr> <tr>
<th>Date</th> <th>Date</th>
<th>Cableur</th> <th>Effectué par</th>
<th>Commentaire</th> <th>Commentaire</th>
</tr> </tr>
</thead> </thead>

View file

@ -40,6 +40,7 @@ from django.conf import settings
from contributors import contributeurs from contributors import contributeurs
import os import os
import time import time
from itertools import chain
import users, preferences, cotisations, topologie, machines import users, preferences, cotisations, topologie, machines
def form(ctx, template, request): def form(ctx, template, request):
@ -88,7 +89,7 @@ HISTORY_BIND = {
'machines' : { 'machines' : {
'machine' : machines.models.Machine, 'machine' : machines.models.Machine,
'interface' : machines.models.Interface, 'interface' : machines.models.Interface,
'alias' : machines.models.Domain, 'domain' : machines.models.Domain,
'machinetype' : machines.models.MachineType, 'machinetype' : machines.models.MachineType,
'iptype' : machines.models.IpType, 'iptype' : machines.models.IpType,
'extension' : machines.models.Extension, 'extension' : machines.models.Extension,
@ -146,6 +147,9 @@ def history(request, application, object_name, object_id):
)) ))
pagination_number = GeneralOption.get_cached_value('pagination_number') pagination_number = GeneralOption.get_cached_value('pagination_number')
reversions = Version.objects.get_for_object(instance) reversions = Version.objects.get_for_object(instance)
if hasattr(instance, 'linked_objects'):
for related_object in chain(instance.linked_objects()):
reversions = reversions | Version.objects.get_for_object(related_object)
paginator = Paginator(reversions, pagination_number) paginator = Paginator(reversions, pagination_number)
page = request.GET.get('page') page = request.GET.get('page')
try: try:

View file

@ -50,9 +50,9 @@ from .models import (
ConstructorSwitch, ConstructorSwitch,
AccessPoint AccessPoint
) )
from re2o.mixins import FormRevMixin
class PortForm(FormRevMixin, ModelForm):
class PortForm(ModelForm):
"""Formulaire pour la création d'un port d'un switch """Formulaire pour la création d'un port d'un switch
Relié directement au modèle port""" Relié directement au modèle port"""
class Meta: class Meta:
@ -64,7 +64,7 @@ class PortForm(ModelForm):
super(PortForm, self).__init__(*args, prefix=prefix, **kwargs) super(PortForm, self).__init__(*args, prefix=prefix, **kwargs)
class EditPortForm(ModelForm): class EditPortForm(FormRevMixin, ModelForm):
"""Form pour l'édition d'un port de switche : changement des reglages """Form pour l'édition d'un port de switche : changement des reglages
radius ou vlan, ou attribution d'une chambre, autre port ou machine radius ou vlan, ou attribution d'une chambre, autre port ou machine
@ -89,7 +89,7 @@ class EditPortForm(ModelForm):
)) ))
class AddPortForm(ModelForm): class AddPortForm(FormRevMixin, ModelForm):
"""Permet d'ajouter un port de switch. Voir EditPortForm pour plus """Permet d'ajouter un port de switch. Voir EditPortForm pour plus
d'informations""" d'informations"""
class Meta(PortForm.Meta): class Meta(PortForm.Meta):
@ -108,7 +108,7 @@ class AddPortForm(ModelForm):
)) ))
class StackForm(ModelForm): class StackForm(FormRevMixin, ModelForm):
"""Permet d'edition d'une stack : stack_id, et switches membres """Permet d'edition d'une stack : stack_id, et switches membres
de la stack""" de la stack"""
class Meta: class Meta:
@ -149,7 +149,7 @@ class NewSwitchForm(NewMachineForm):
fields = ['name', 'location', 'number', 'stack', 'stack_member_id'] fields = ['name', 'location', 'number', 'stack', 'stack_member_id']
class EditRoomForm(ModelForm): class EditRoomForm(FormRevMixin, ModelForm):
"""Permet d'éediter le nom et commentaire d'une prise murale""" """Permet d'éediter le nom et commentaire d'une prise murale"""
class Meta: class Meta:
model = Room model = Room
@ -166,7 +166,7 @@ class CreatePortsForm(forms.Form):
end = forms.IntegerField(label="Fin :", min_value=0) end = forms.IntegerField(label="Fin :", min_value=0)
class EditModelSwitchForm(ModelForm): class EditModelSwitchForm(FormRevMixin, ModelForm):
"""Permet d'éediter un modèle de switch : nom et constructeur""" """Permet d'éediter un modèle de switch : nom et constructeur"""
class Meta: class Meta:
model = ModelSwitch model = ModelSwitch
@ -177,7 +177,7 @@ class EditModelSwitchForm(ModelForm):
super(EditModelSwitchForm, self).__init__(*args, prefix=prefix, **kwargs) super(EditModelSwitchForm, self).__init__(*args, prefix=prefix, **kwargs)
class EditConstructorSwitchForm(ModelForm): class EditConstructorSwitchForm(FormRevMixin, ModelForm):
"""Permet d'éediter le nom d'un constructeur""" """Permet d'éediter le nom d'un constructeur"""
class Meta: class Meta:
model = ConstructorSwitch model = ConstructorSwitch

View file

@ -0,0 +1,228 @@
# -*- coding: utf-8 -*-
import sys
import json
import six
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from topologie.management.modelviz import ModelGraph, generate_dot
from django_extensions.management.utils import signalcommand
try:
import pygraphviz
HAS_PYGRAPHVIZ = True
except ImportError:
HAS_PYGRAPHVIZ = False
try:
try:
import pydotplus as pydot
except ImportError:
import pydot
HAS_PYDOT = True
except ImportError:
HAS_PYDOT = False
class Command(BaseCommand):
help = "Creates a GraphViz dot file for the specified app names. You can pass multiple app names and they will all be combined into a single model. Output is usually directed to a dot file."
can_import_settings = True
def __init__(self, *args, **kwargs):
"""Allow defaults for arguments to be set in settings.GRAPH_MODELS.
Each argument in self.arguments is a dict where the key is the
space-separated args and the value is our kwarg dict.
The default from settings is keyed as the long arg name with '--'
removed and any '-' replaced by '_'.
"""
self.arguments = {
'--pygraphviz': {
'action': 'store_true', 'dest': 'pygraphviz',
'help': 'Use PyGraphViz to generate the image.'},
'--pydot': {'action': 'store_true', 'dest': 'pydot',
'help': 'Use PyDot(Plus) to generate the image.'},
'--disable-fields -d': {
'action': 'store_true', 'dest': 'disable_fields',
'help': 'Do not show the class member fields'},
'--group-models -g': {
'action': 'store_true', 'dest': 'group_models',
'help': 'Group models together respective to their '
'application'},
'--all-applications -a': {
'action': 'store_true', 'dest': 'all_applications',
'help': 'Automatically include all applications from '
'INSTALLED_APPS'},
'--output -o': {
'action': 'store', 'dest': 'outputfile',
'help': 'Render output file. Type of output dependend on file '
'extensions. Use png or jpg to render graph to image.'},
'--layout -l': {
'action': 'store', 'dest': 'layout', 'default': 'dot',
'help': 'Layout to be used by GraphViz for visualization. '
'Layouts: circo dot fdp neato nop nop1 nop2 twopi'},
'--verbose-names -n': {
'action': 'store_true', 'dest': 'verbose_names',
'help': 'Use verbose_name of models and fields'},
'--language -L': {
'action': 'store', 'dest': 'language',
'help': 'Specify language used for verbose_name localization'},
'--exclude-columns -x': {
'action': 'store', 'dest': 'exclude_columns',
'help': 'Exclude specific column(s) from the graph. '
'Can also load exclude list from file.'},
'--exclude-models -X': {
'action': 'store', 'dest': 'exclude_models',
'help': 'Exclude specific model(s) from the graph. Can also '
'load exclude list from file. Wildcards (*) are allowed.'},
'--include-models -I': {
'action': 'store', 'dest': 'include_models',
'help': 'Restrict the graph to specified models. Wildcards '
'(*) are allowed.'},
'--inheritance -e': {
'action': 'store_true', 'dest': 'inheritance', 'default': True,
'help': 'Include inheritance arrows (default)'},
'--no-inheritance -E': {
'action': 'store_false', 'dest': 'inheritance',
'help': 'Do not include inheritance arrows'},
'--hide-relations-from-fields -R': {
'action': 'store_false', 'dest': 'relations_as_fields',
'default': True,
'help': 'Do not show relations as fields in the graph.'},
'--disable-sort-fields -S': {
'action': 'store_false', 'dest': 'sort_fields',
'default': True, 'help': 'Do not sort fields'},
'--json': {'action': 'store_true', 'dest': 'json',
'help': 'Output graph data as JSON'}
}
defaults = getattr(settings, 'GRAPH_MODELS', None)
if defaults:
for argument in self.arguments:
arg_split = argument.split(' ')
setting_opt = arg_split[0].lstrip('-').replace('-', '_')
if setting_opt in defaults:
self.arguments[argument]['default'] = defaults[setting_opt]
super(Command, self).__init__(*args, **kwargs)
def add_arguments(self, parser):
"""Unpack self.arguments for parser.add_arguments."""
parser.add_argument('app_label', nargs='*')
for argument in self.arguments:
parser.add_argument(*argument.split(' '),
**self.arguments[argument])
@signalcommand
def handle(self, *args, **options):
args = options['app_label']
if len(args) < 1 and not options['all_applications']:
raise CommandError("need one or more arguments for appname")
use_pygraphviz = options.get('pygraphviz', False)
use_pydot = options.get('pydot', False)
use_json = options.get('json', False)
if use_json and (use_pydot or use_pygraphviz):
raise CommandError("Cannot specify --json with --pydot or --pygraphviz")
cli_options = ' '.join(sys.argv[2:])
graph_models = ModelGraph(args, cli_options=cli_options, **options)
graph_models.generate_graph_data()
graph_data = graph_models.get_graph_data(as_json=use_json)
if use_json:
self.render_output_json(graph_data, **options)
return
dotdata = generate_dot(graph_data)
if not six.PY3:
dotdata = dotdata.encode('utf-8')
if options['outputfile']:
if not use_pygraphviz and not use_pydot:
if HAS_PYGRAPHVIZ:
use_pygraphviz = True
elif HAS_PYDOT:
use_pydot = True
if use_pygraphviz:
self.render_output_pygraphviz(dotdata, **options)
elif use_pydot:
self.render_output_pydot(dotdata, **options)
else:
raise CommandError("Neither pygraphviz nor pydotplus could be found to generate the image")
else:
self.print_output(dotdata)
def print_output(self, dotdata):
if six.PY3 and isinstance(dotdata, six.binary_type):
dotdata = dotdata.decode()
print(dotdata)
def render_output_json(self, graph_data, **kwargs):
output_file = kwargs.get('outputfile')
if output_file:
with open(output_file, 'wt') as json_output_f:
json.dump(graph_data, json_output_f)
else:
print(json.dumps(graph_data))
def render_output_pygraphviz(self, dotdata, **kwargs):
"""Renders the image using pygraphviz"""
if not HAS_PYGRAPHVIZ:
raise CommandError("You need to install pygraphviz python module")
version = pygraphviz.__version__.rstrip("-svn")
try:
if tuple(int(v) for v in version.split('.')) < (0, 36):
# HACK around old/broken AGraph before version 0.36 (ubuntu ships with this old version)
import tempfile
tmpfile = tempfile.NamedTemporaryFile()
tmpfile.write(dotdata)
tmpfile.seek(0)
dotdata = tmpfile.name
except ValueError:
pass
graph = pygraphviz.AGraph(dotdata)
graph.layout(prog=kwargs['layout'])
graph.draw(kwargs['outputfile'])
def render_output_pydot(self, dotdata, **kwargs):
"""Renders the image using pydot"""
if not HAS_PYDOT:
raise CommandError("You need to install pydot python module")
graph = pydot.graph_from_dot_data(dotdata)
if not graph:
raise CommandError("pydot returned an error")
if isinstance(graph, (list, tuple)):
if len(graph) > 1:
sys.stderr.write("Found more then one graph, rendering only the first one.\n")
graph = graph[0]
output_file = kwargs['outputfile']
formats = ['bmp', 'canon', 'cmap', 'cmapx', 'cmapx_np', 'dot', 'dia', 'emf',
'em', 'fplus', 'eps', 'fig', 'gd', 'gd2', 'gif', 'gv', 'imap',
'imap_np', 'ismap', 'jpe', 'jpeg', 'jpg', 'metafile', 'pdf',
'pic', 'plain', 'plain-ext', 'png', 'pov', 'ps', 'ps2', 'svg',
'svgz', 'tif', 'tiff', 'tk', 'vml', 'vmlz', 'vrml', 'wbmp', 'xdot']
ext = output_file[output_file.rfind('.') + 1:]
format = ext if ext in formats else 'raw'
graph.write(output_file, format=format)

View file

@ -0,0 +1,405 @@
# -*- coding: utf-8 -*-
"""
modelviz.py - DOT file generator for Django Models
Based on:
Django model to DOT (Graphviz) converter
by Antonio Cavedoni <antonio@cavedoni.org>
Adapted to be used with django-extensions
"""
import datetime
import os
import re
import six
from django.apps import apps
from django.db.models.fields.related import (
ForeignKey, ManyToManyField, OneToOneField, RelatedField,
)
from django.contrib.contenttypes.fields import GenericRelation
from django.template import Context, Template, loader
from django.utils.encoding import force_bytes, force_str
from django.utils.safestring import mark_safe
from django.utils.translation import activate as activate_language
__version__ = "1.1"
__license__ = "Python"
__author__ = "Bas van Oostveen <v.oostveen@gmail.com>",
__contributors__ = [
"Antonio Cavedoni <http://cavedoni.com/>"
"Stefano J. Attardi <http://attardi.org/>",
"limodou <http://www.donews.net/limodou/>",
"Carlo C8E Miron",
"Andre Campos <cahenan@gmail.com>",
"Justin Findlay <jfindlay@gmail.com>",
"Alexander Houben <alexander@houben.ch>",
"Joern Hees <gitdev@joernhees.de>",
"Kevin Cherepski <cherepski@gmail.com>",
"Jose Tomas Tocino <theom3ga@gmail.com>",
"Adam Dobrawy <naczelnik@jawnosc.tk>",
"Mikkel Munch Mortensen <https://www.detfalskested.dk/>",
"Andrzej Bistram <andrzej.bistram@gmail.com>",
]
def parse_file_or_list(arg):
if not arg:
return []
if isinstance(arg, (list, tuple, set)):
return arg
if ',' not in arg and os.path.isfile(arg):
return [e.strip() for e in open(arg).readlines()]
return [e.strip() for e in arg.split(',')]
class ModelGraph(object):
def __init__(self, app_labels, **kwargs):
self.graphs = []
self.cli_options = kwargs.get('cli_options', None)
self.disable_fields = kwargs.get('disable_fields', False)
self.include_models = parse_file_or_list(
kwargs.get('include_models', "")
)
self.all_applications = kwargs.get('all_applications', False)
self.use_subgraph = kwargs.get('group_models', False)
self.verbose_names = kwargs.get('verbose_names', False)
self.inheritance = kwargs.get('inheritance', True)
self.relations_as_fields = kwargs.get("relations_as_fields", True)
self.sort_fields = kwargs.get("sort_fields", True)
self.language = kwargs.get('language', None)
if self.language is not None:
activate_language(self.language)
self.exclude_columns = parse_file_or_list(
kwargs.get('exclude_columns', "")
)
self.exclude_models = parse_file_or_list(
kwargs.get('exclude_models', "")
)
if self.all_applications:
self.app_labels = [app.label for app in apps.get_app_configs()]
else:
self.app_labels = app_labels
def generate_graph_data(self):
self.process_apps()
nodes = []
for graph in self.graphs:
nodes.extend([e['name'] for e in graph['models']])
for graph in self.graphs:
for model in graph['models']:
for relation in model['relations']:
if relation is not None:
if relation['target'] in nodes:
relation['needs_node'] = False
def get_graph_data(self, as_json=False):
now = datetime.datetime.now()
graph_data = {
'created_at': now.strftime("%Y-%m-%d %H:%M"),
'cli_options': self.cli_options,
'disable_fields': self.disable_fields,
'use_subgraph': self.use_subgraph,
}
if as_json:
graph_data['graphs'] = [context.flatten() for context in self.graphs]
else:
graph_data['graphs'] = self.graphs
return graph_data
def add_attributes(self, field, abstract_fields):
if self.verbose_names and field.verbose_name:
label = force_bytes(field.verbose_name)
if label.islower():
label = label.capitalize()
else:
label = field.name
t = type(field).__name__
if isinstance(field, (OneToOneField, ForeignKey)):
remote_field = field.remote_field if hasattr(field, 'remote_field') else field.rel # Remove me after Django 1.8 is unsupported
t += " ({0})".format(remote_field.field_name)
# TODO: ManyToManyField, GenericRelation
return {
'name': field.name,
'label': label,
'type': t,
'blank': field.blank,
'abstract': field in abstract_fields,
'relation': isinstance(field, RelatedField),
'primary_key': field.primary_key,
}
def add_relation(self, field, model, extras=""):
if self.verbose_names and field.verbose_name:
label = force_bytes(field.verbose_name)
if label.islower():
label = label.capitalize()
else:
label = field.name
# show related field name
if hasattr(field, 'related_query_name'):
related_query_name = field.related_query_name()
if self.verbose_names and related_query_name.islower():
related_query_name = related_query_name.replace('_', ' ').capitalize()
label = '{} ({})'.format(label, force_str(related_query_name))
# handle self-relationships and lazy-relationships
remote_field = field.remote_field if hasattr(field, 'remote_field') else field.rel # Remove me after Django 1.8 is unsupported
remote_field_model = remote_field.model if hasattr(remote_field, 'model') else remote_field.to # Remove me after Django 1.8 is unsupported
if isinstance(remote_field_model, six.string_types):
if remote_field_model == 'self':
target_model = field.model
else:
if '.' in remote_field_model:
app_label, model_name = remote_field_model.split('.', 1)
else:
app_label = field.model._meta.app_label
model_name = remote_field_model
target_model = apps.get_model(app_label, model_name)
else:
target_model = remote_field_model
_rel = self.get_relation_context(target_model, field, label, extras)
if _rel not in model['relations'] and self.use_model(_rel['target']):
return _rel
def get_abstract_models(self, appmodels):
abstract_models = []
for appmodel in appmodels:
abstract_models += [abstract_model for abstract_model in
appmodel.__bases__ if
hasattr(abstract_model, '_meta') and
abstract_model._meta.abstract]
abstract_models = list(set(abstract_models)) # remove duplicates
return abstract_models
def get_app_context(self, app):
return Context({
'name': '"%s"' % app.name,
'app_name': "%s" % app.name,
'cluster_app_name': "cluster_%s" % app.name.replace(".", "_"),
'models': []
})
def get_appmodel_attributes(self, appmodel):
if self.relations_as_fields:
attributes = [field for field in appmodel._meta.local_fields]
else:
# Find all the 'real' attributes. Relations are depicted as graph edges instead of attributes
attributes = [field for field in appmodel._meta.local_fields if not
isinstance(field, RelatedField)]
return attributes
def get_appmodel_abstracts(self, appmodel):
return [abstract_model.__name__ for abstract_model in
appmodel.__bases__ if
hasattr(abstract_model, '_meta') and
abstract_model._meta.abstract]
def get_appmodel_context(self, appmodel, appmodel_abstracts):
context = {
'app_name': appmodel.__module__.replace(".", "_"),
'name': appmodel.__name__,
'abstracts': appmodel_abstracts,
'fields': [],
'relations': []
}
if self.verbose_names and appmodel._meta.verbose_name:
context['label'] = force_bytes(appmodel._meta.verbose_name)
else:
context['label'] = context['name']
return context
def get_bases_abstract_fields(self, c):
_abstract_fields = []
for e in c.__bases__:
if hasattr(e, '_meta') and e._meta.abstract:
_abstract_fields.extend(e._meta.fields)
_abstract_fields.extend(self.get_bases_abstract_fields(e))
return _abstract_fields
def get_inheritance_context(self, appmodel, parent):
label = "multi-table"
if parent._meta.abstract:
label = "abstract"
if appmodel._meta.proxy:
label = "proxy"
label += r"\ninheritance"
return {
'target_app': parent.__module__.replace(".", "_"),
'target': parent.__name__,
'type': "inheritance",
'name': "inheritance",
'label': label,
'arrows': '[arrowhead=empty, arrowtail=none, dir=both]',
'needs_node': True,
}
def get_models(self, app):
appmodels = list(app.get_models())
return appmodels
def get_relation_context(self, target_model, field, label, extras):
return {
'target_app': target_model.__module__.replace('.', '_'),
'target': target_model.__name__,
'type': type(field).__name__,
'name': field.name,
'label': label,
'arrows': extras,
'needs_node': True
}
def process_attributes(self, field, model, pk, abstract_fields):
newmodel = model.copy()
if self.skip_field(field) or pk and field == pk:
return newmodel
newmodel['fields'].append(self.add_attributes(field, abstract_fields))
return newmodel
def process_apps(self):
for app_label in self.app_labels:
app = apps.get_app_config(app_label)
if not app:
continue
app_graph = self.get_app_context(app)
app_models = self.get_models(app)
abstract_models = self.get_abstract_models(app_models)
app_models = abstract_models + app_models
for appmodel in app_models:
if not self.use_model(appmodel._meta.object_name):
continue
appmodel_abstracts = self.get_appmodel_abstracts(appmodel)
abstract_fields = self.get_bases_abstract_fields(appmodel)
model = self.get_appmodel_context(appmodel, appmodel_abstracts)
attributes = self.get_appmodel_attributes(appmodel)
# find primary key and print it first, ignoring implicit id if other pk exists
pk = appmodel._meta.pk
if pk and not appmodel._meta.abstract and pk in attributes:
model['fields'].append(self.add_attributes(pk, abstract_fields))
for field in attributes:
model = self.process_attributes(field, model, pk, abstract_fields)
if self.sort_fields:
model = self.sort_model_fields(model)
for field in appmodel._meta.local_fields:
model = self.process_local_fields(field, model, abstract_fields)
for field in appmodel._meta.local_many_to_many:
model = self.process_local_many_to_many(field, model)
if self.inheritance:
# add inheritance arrows
for parent in appmodel.__bases__:
model = self.process_parent(parent, appmodel, model)
app_graph['models'].append(model)
if app_graph['models']:
self.graphs.append(app_graph)
def process_local_fields(self, field, model, abstract_fields):
newmodel = model.copy()
if (field.attname.endswith('_ptr_id') or # excluding field redundant with inheritance relation
field in abstract_fields or # excluding fields inherited from abstract classes. they too show as local_fields
self.skip_field(field)):
return newmodel
if isinstance(field, OneToOneField):
newmodel['relations'].append(self.add_relation(field, newmodel, '[arrowhead=none, arrowtail=none, dir=both]'))
elif isinstance(field, ForeignKey):
newmodel['relations'].append(self.add_relation(field, newmodel, '[arrowhead=none, arrowtail=dot, dir=both]'))
return newmodel
def process_local_many_to_many(self, field, model):
newmodel = model.copy()
if self.skip_field(field):
return newmodel
if isinstance(field, ManyToManyField):
remote_field = field.remote_field if hasattr(field, 'remote_field') else field.rel # Remove me after Django 1.8 is unsupported
if hasattr(remote_field.through, '_meta') and remote_field.through._meta.auto_created:
newmodel['relations'].append(self.add_relation(field, newmodel, '[arrowhead=dot arrowtail=dot, dir=both]'))
elif isinstance(field, GenericRelation):
newmodel['relations'].append(self.add_relation(field, newmodel, mark_safe('[style="dotted", arrowhead=normal, arrowtail=normal, dir=both]')))
return newmodel
def process_parent(self, parent, appmodel, model):
newmodel = model.copy()
if hasattr(parent, "_meta"): # parent is a model
_rel = self.get_inheritance_context(appmodel, parent)
# TODO: seems as if abstract models aren't part of models.getModels, which is why they are printed by this without any attributes.
if _rel not in newmodel['relations'] and self.use_model(_rel['target']):
newmodel['relations'].append(_rel)
return newmodel
def sort_model_fields(self, model):
newmodel = model.copy()
newmodel['fields'] = sorted(newmodel['fields'], key=lambda field: (not field['primary_key'], not field['relation'], field['label']))
return newmodel
def use_model(self, model_name):
"""
Decide whether to use a model, based on the model name and the lists of
models to exclude and include.
"""
# Check against exclude list.
if self.exclude_models:
for model_pattern in self.exclude_models:
model_pattern = '^%s$' % model_pattern.replace('*', '.*')
if re.search(model_pattern, model_name):
return False
# Check against exclude list.
elif self.include_models:
for model_pattern in self.include_models:
model_pattern = '^%s$' % model_pattern.replace('*', '.*')
if re.search(model_pattern, model_name):
return True
# Return `True` if `include_models` is falsey, otherwise return `False`.
return not self.include_models
def skip_field(self, field):
if self.exclude_columns:
if self.verbose_names and field.verbose_name:
if field.verbose_name in self.exclude_columns:
return True
if field.name in self.exclude_columns:
return True
return False
def generate_dot(graph_data, template='django_extensions/graph_models/digraph.dot'):
t = loader.get_template(template)
if not isinstance(t, Template) and not (hasattr(t, 'template') and isinstance(t.template, Template)):
raise Exception("Default Django template loader isn't used. "
"This can lead to the incorrect template rendering. "
"Please, check the settings.")
c = Context(graph_data).flatten()
dot = t.render(c)
return dot
def generate_graph_data(*args, **kwargs):
generator = ModelGraph(*args, **kwargs)
generator.generate_graph_data()
return generator.get_graph_data()
def use_model(model, include_models, exclude_models):
generator = ModelGraph([], include_models=include_models, exclude_models=exclude_models)
return generator.use_model(model)

View file

@ -48,9 +48,9 @@ from django.db import transaction
from reversion import revisions as reversion from reversion import revisions as reversion
from machines.models import Machine, Interface, regen from machines.models import Machine, Interface, regen
from re2o.mixins import AclMixin from re2o.mixins import AclMixin, RevMixin
class Stack(AclMixin, models.Model): class Stack(AclMixin, RevMixin, models.Model):
"""Un objet stack. Regrouppe des switchs en foreign key """Un objet stack. Regrouppe des switchs en foreign key
,contient une id de stack, un switch id min et max dans ,contient une id de stack, un switch id min et max dans
le stack""" le stack"""
@ -102,6 +102,9 @@ class AccessPoint(AclMixin, Machine):
("view_accesspoint", "Peut voir une borne"), ("view_accesspoint", "Peut voir une borne"),
) )
def __str__(self):
return str(self.interface_set.first())
class Switch(AclMixin, Machine): class Switch(AclMixin, Machine):
""" Definition d'un switch. Contient un nombre de ports (number), """ Definition d'un switch. Contient un nombre de ports (number),
@ -187,7 +190,7 @@ class Switch(AclMixin, Machine):
return str(self.interface_set.first()) return str(self.interface_set.first())
class ModelSwitch(AclMixin, models.Model): class ModelSwitch(AclMixin, RevMixin, models.Model):
"""Un modèle (au sens constructeur) de switch""" """Un modèle (au sens constructeur) de switch"""
PRETTY_NAME = "Modèle de switch" PRETTY_NAME = "Modèle de switch"
reference = models.CharField(max_length=255) reference = models.CharField(max_length=255)
@ -205,7 +208,7 @@ class ModelSwitch(AclMixin, models.Model):
return str(self.constructor) + ' ' + self.reference return str(self.constructor) + ' ' + self.reference
class ConstructorSwitch(AclMixin, models.Model): class ConstructorSwitch(AclMixin, RevMixin, models.Model):
"""Un constructeur de switch""" """Un constructeur de switch"""
PRETTY_NAME = "Constructeur de switch" PRETTY_NAME = "Constructeur de switch"
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
@ -219,7 +222,7 @@ class ConstructorSwitch(AclMixin, models.Model):
return self.name return self.name
class Port(AclMixin, models.Model): class Port(AclMixin, RevMixin, models.Model):
""" Definition d'un port. Relié à un switch(foreign_key), """ Definition d'un port. Relié à un switch(foreign_key),
un port peut etre relié de manière exclusive à : un port peut etre relié de manière exclusive à :
- une chambre (room) - une chambre (room)
@ -335,7 +338,7 @@ class Port(AclMixin, models.Model):
return str(self.switch) + " - " + str(self.port) return str(self.switch) + " - " + str(self.port)
class Room(AclMixin, models.Model): class Room(AclMixin, RevMixin, models.Model):
"""Une chambre/local contenant une prise murale""" """Une chambre/local contenant une prise murale"""
PRETTY_NAME = "Chambre/ Prise murale" PRETTY_NAME = "Chambre/ Prise murale"

View file

@ -24,6 +24,64 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load acl %} {% load acl %}
<div class="table-responsive" style="font-size: 12px">
<table class="table table-bordered text-center text-nowrap">
<thead>
<tr>
{% for port in port_list|slice:"::2" %}
<td class="bg-primary text-white">{{ port.port }}</td>
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"::2" %}
<td class="p-3 mb-2 bg-success text-dark">
{% if port.room %}
{{ port.room }}
{% elif port.machine_interface %}
<a href="{% url 'users:profil' userid=port.machine_interface.machine.user.id %}">{{ port.machine_interface }}</a>
{% elif port.related%}
<a href="{% url 'topologie:index-port' switchid=port.related.switch.id %}">{{ port.related }}</a>
{% else %}
Vide
{% endif %}
</td>
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"1::2" %}
<td class="bg-primary text-white">{{ port.port }}</td>
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"1::2" %}
<td class="p-3 mb-2 bg-success text-dark">
{% if port.room %}
{{ port.room }}
{% elif port.machine_interface %}
<a href="{% url 'users:profil' userid=port.machine_interface.machine.user.id %}">{{ port.machine_interface }}</a>
{% elif port.related%}
<a href="{% url 'topologie:index-port' switchid=port.related.switch.id %}">{{ port.related }}</a>
{% else %}
Vide
{% endif %}
</td>
{% endfor %}
</tr>
</table>
</div>
<div class="table-responsive">
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
@ -76,3 +134,4 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div>

View file

@ -35,7 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:new-port' id_switch %}"><i class="fa fa-plus"></i> Ajouter un port</a> <a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:new-port' id_switch %}"><i class="fa fa-plus"></i> Ajouter un port</a>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:create-ports' id_switch %}"><i class="fa fa-plus"></i> Ajouter des ports</a> <a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:create-ports' id_switch %}"><i class="fa fa-plus"></i> Ajouter des ports</a>
{% acl_end %} {% acl_end %}
{% include "topologie/aff_port.html" with port_list=port_list %} <hr>
{% include "topologie/aff_port.html" with port_list=port_list %}
<br /> <br />
<br /> <br />
<br /> <br />

View file

@ -44,8 +44,6 @@ from django.db import transaction
from django.db.models import ProtectedError, Prefetch from django.db.models import ProtectedError, Prefetch
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from reversion import revisions as reversion
from reversion.models import Version
from topologie.models import ( from topologie.models import (
Switch, Switch,
@ -262,10 +260,7 @@ def new_port(request, switchid):
port = port.save(commit=False) port = port.save(commit=False)
port.switch = switch port.switch = switch
try: try:
with transaction.atomic(), reversion.create_revision(): port.save()
port.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Port ajouté") messages.success(request, "Port ajouté")
except IntegrityError: except IntegrityError:
messages.error(request, "Ce port existe déjà") messages.error(request, "Ce port existe déjà")
@ -284,13 +279,9 @@ def edit_port(request, port_object, portid):
port = EditPortForm(request.POST or None, instance=port_object) port = EditPortForm(request.POST or None, instance=port_object)
if port.is_valid(): if port.is_valid():
with transaction.atomic(), reversion.create_revision(): if port.changed_data:
port.save() port.save()
reversion.set_user(request.user) messages.success(request, "Le port a bien été modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in port.changed_data
))
messages.success(request, "Le port a bien été modifié")
return redirect(reverse( return redirect(reverse(
'topologie:index-port', 'topologie:index-port',
kwargs={'switchid': str(port_object.switch.id)} kwargs={'switchid': str(port_object.switch.id)}
@ -304,11 +295,8 @@ def del_port(request, port, portid):
""" Supprime le port""" """ Supprime le port"""
if request.method == "POST": if request.method == "POST":
try: try:
with transaction.atomic(), reversion.create_revision(): port.delete()
port.delete() messages.success(request, "Le port a été détruit")
reversion.set_user(request.user)
reversion.set_comment("Destruction")
messages.success(request, "Le port a été détruit")
except ProtectedError: except ProtectedError:
messages.error(request, "Le port %s est affecté à un autre objet,\ messages.error(request, "Le port %s est affecté à un autre objet,\
impossible de le supprimer" % port) impossible de le supprimer" % port)
@ -325,10 +313,7 @@ def new_stack(request):
"""Ajoute un nouveau stack : stackid_min, max, et nombre de switches""" """Ajoute un nouveau stack : stackid_min, max, et nombre de switches"""
stack = StackForm(request.POST or None) stack = StackForm(request.POST or None)
if stack.is_valid(): if stack.is_valid():
with transaction.atomic(), reversion.create_revision(): stack.save()
stack.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Stack crée") messages.success(request, "Stack crée")
return form({'topoform': stack, 'action_name' : 'Créer'}, 'topologie/topo.html', request) return form({'topoform': stack, 'action_name' : 'Créer'}, 'topologie/topo.html', request)
@ -337,17 +322,10 @@ def new_stack(request):
@can_edit(Stack) @can_edit(Stack)
def edit_stack(request, stack, stackid): def edit_stack(request, stack, stackid):
"""Edition d'un stack (nombre de switches, nom...)""" """Edition d'un stack (nombre de switches, nom...)"""
stack = StackForm(request.POST or None, instance=stack) stack = StackForm(request.POST or None, instance=stack)
if stack.is_valid(): if stack.is_valid():
with transaction.atomic(), reversion.create_revision(): if stack.changed_data:
stack.save() stack.save()
reversion.set_user(request.user)
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in stack.changed_data
)
)
return redirect(reverse('topologie:index-stack')) return redirect(reverse('topologie:index-stack'))
return form({'topoform': stack, 'action_name' : 'Editer'}, 'topologie/topo.html', request) return form({'topoform': stack, 'action_name' : 'Editer'}, 'topologie/topo.html', request)
@ -358,11 +336,8 @@ def del_stack(request, stack, stackid):
"""Supprime un stack""" """Supprime un stack"""
if request.method == "POST": if request.method == "POST":
try: try:
with transaction.atomic(), reversion.create_revision(): stack.delete()
stack.delete() messages.success(request, "La stack a eté détruite")
reversion.set_user(request.user)
reversion.set_comment("Destruction")
messages.success(request, "La stack a eté détruite")
except ProtectedError: except ProtectedError:
messages.error(request, "La stack %s est affectée à un autre\ messages.error(request, "La stack %s est affectée à un autre\
objet, impossible de la supprimer" % stack) objet, impossible de la supprimer" % stack)
@ -412,20 +387,11 @@ def new_switch(request):
domain.instance.interface_parent = new_interface_instance domain.instance.interface_parent = new_interface_instance
if domain.is_valid(): if domain.is_valid():
new_domain_instance = domain.save(commit=False) new_domain_instance = domain.save(commit=False)
with transaction.atomic(), reversion.create_revision(): new_switch.save()
new_switch.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_interface_instance.machine = new_switch new_interface_instance.machine = new_switch
with transaction.atomic(), reversion.create_revision(): new_interface_instance.save()
new_interface_instance.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_domain_instance.interface_parent = new_interface_instance new_domain_instance.interface_parent = new_interface_instance
with transaction.atomic(), reversion.create_revision(): new_domain_instance.save()
new_domain_instance.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Le switch a été créé") messages.success(request, "Le switch a été créé")
return redirect(reverse('topologie:index')) return redirect(reverse('topologie:index'))
i_mbf_param = generate_ipv4_mbf_param(interface, False) i_mbf_param = generate_ipv4_mbf_param(interface, False)
@ -468,7 +434,6 @@ def create_ports(request, switchid):
messages.success(request, "Ports créés.") messages.success(request, "Ports créés.")
except ValidationError as e: except ValidationError as e:
messages.error(request, ''.join(e)) messages.error(request, ''.join(e))
return redirect(reverse( return redirect(reverse(
'topologie:index-port', 'topologie:index-port',
kwargs={'switchid':switchid} kwargs={'switchid':switchid}
@ -500,26 +465,12 @@ def edit_switch(request, switch, switchid):
new_switch = switch_form.save(commit=False) new_switch = switch_form.save(commit=False)
new_interface_instance = interface_form.save(commit=False) new_interface_instance = interface_form.save(commit=False)
new_domain = domain_form.save(commit=False) new_domain = domain_form.save(commit=False)
with transaction.atomic(), reversion.create_revision(): if switch_form.changed_data:
new_switch.save() new_switch.save()
reversion.set_user(request.user) if interface_form.changed_data:
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in switch_form.changed_data
)
)
with transaction.atomic(), reversion.create_revision():
new_interface_instance.save() new_interface_instance.save()
reversion.set_user(request.user) if domain_form.changed_data:
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in interface_form.changed_data)
)
with transaction.atomic(), reversion.create_revision():
new_domain.save() new_domain.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in domain_form.changed_data)
)
messages.success(request, "Le switch a bien été modifié") messages.success(request, "Le switch a bien été modifié")
return redirect(reverse('topologie:index')) return redirect(reverse('topologie:index'))
i_mbf_param = generate_ipv4_mbf_param(interface_form, False ) i_mbf_param = generate_ipv4_mbf_param(interface_form, False )
@ -562,20 +513,11 @@ def new_ap(request):
domain.instance.interface_parent = new_interface domain.instance.interface_parent = new_interface
if domain.is_valid(): if domain.is_valid():
new_domain_instance = domain.save(commit=False) new_domain_instance = domain.save(commit=False)
with transaction.atomic(), reversion.create_revision(): new_ap.save()
new_ap.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_interface.machine = new_ap new_interface.machine = new_ap
with transaction.atomic(), reversion.create_revision(): new_interface.save()
new_interface.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
new_domain_instance.interface_parent = new_interface new_domain_instance.interface_parent = new_interface
with transaction.atomic(), reversion.create_revision(): new_domain_instance.save()
new_domain_instance.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "La borne a été créé") messages.success(request, "La borne a été créé")
return redirect(reverse('topologie:index-ap')) return redirect(reverse('topologie:index-ap'))
i_mbf_param = generate_ipv4_mbf_param(interface, False) i_mbf_param = generate_ipv4_mbf_param(interface, False)
@ -616,26 +558,12 @@ def edit_ap(request, ap, accesspointid):
new_ap = ap_form.save(commit=False) new_ap = ap_form.save(commit=False)
new_interface = interface_form.save(commit=False) new_interface = interface_form.save(commit=False)
new_domain = domain_form.save(commit=False) new_domain = domain_form.save(commit=False)
with transaction.atomic(), reversion.create_revision(): if ap_form.changed_data:
new_ap.save() new_ap.save()
reversion.set_user(request.user) if interface_form.changed_data:
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in ap_form.changed_data)
)
with transaction.atomic(), reversion.create_revision():
new_interface.save() new_interface.save()
reversion.set_user(request.user) if domain_form.changed_data:
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in interface_form.changed_data)
)
reversion.set_comment("Création")
with transaction.atomic(), reversion.create_revision():
new_domain.save() new_domain.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in domain_form.changed_data)
)
messages.success(request, "La borne a été modifiée") messages.success(request, "La borne a été modifiée")
return redirect(reverse('topologie:index-ap')) return redirect(reverse('topologie:index-ap'))
i_mbf_param = generate_ipv4_mbf_param(interface_form, False ) i_mbf_param = generate_ipv4_mbf_param(interface_form, False )
@ -654,10 +582,7 @@ def new_room(request):
"""Nouvelle chambre """ """Nouvelle chambre """
room = EditRoomForm(request.POST or None) room = EditRoomForm(request.POST or None)
if room.is_valid(): if room.is_valid():
with transaction.atomic(), reversion.create_revision(): room.save()
room.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "La chambre a été créé") messages.success(request, "La chambre a été créé")
return redirect(reverse('topologie:index-room')) return redirect(reverse('topologie:index-room'))
return form({'topoform': room, 'action_name' : 'Ajouter'}, 'topologie/topo.html', request) return form({'topoform': room, 'action_name' : 'Ajouter'}, 'topologie/topo.html', request)
@ -667,16 +592,11 @@ def new_room(request):
@can_edit(Room) @can_edit(Room)
def edit_room(request, room, roomid): def edit_room(request, room, roomid):
""" Edition numero et details de la chambre""" """ Edition numero et details de la chambre"""
room = EditRoomForm(request.POST or None, instance=room) room = EditRoomForm(request.POST or None, instance=room)
if room.is_valid(): if room.is_valid():
with transaction.atomic(), reversion.create_revision(): if room.changed_data:
room.save() room.save()
reversion.set_user(request.user) messages.success(request, "La chambre a bien été modifiée")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in room.changed_data)
)
messages.success(request, "La chambre a bien été modifiée")
return redirect(reverse('topologie:index-room')) return redirect(reverse('topologie:index-room'))
return form({'topoform': room, 'action_name' : 'Editer'}, 'topologie/topo.html', request) return form({'topoform': room, 'action_name' : 'Editer'}, 'topologie/topo.html', request)
@ -687,11 +607,8 @@ def del_room(request, room, roomid):
""" Suppression d'un chambre""" """ Suppression d'un chambre"""
if request.method == "POST": if request.method == "POST":
try: try:
with transaction.atomic(), reversion.create_revision(): room.delete()
room.delete() messages.success(request, "La chambre/prise a été détruite")
reversion.set_user(request.user)
reversion.set_comment("Destruction")
messages.success(request, "La chambre/prise a été détruite")
except ProtectedError: except ProtectedError:
messages.error(request, "La chambre %s est affectée à un autre objet,\ messages.error(request, "La chambre %s est affectée à un autre objet,\
impossible de la supprimer (switch ou user)" % room) impossible de la supprimer (switch ou user)" % room)
@ -708,10 +625,7 @@ def new_model_switch(request):
"""Nouveau modèle de switch""" """Nouveau modèle de switch"""
model_switch = EditModelSwitchForm(request.POST or None) model_switch = EditModelSwitchForm(request.POST or None)
if model_switch.is_valid(): if model_switch.is_valid():
with transaction.atomic(), reversion.create_revision(): model_switch.save()
model_switch.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Le modèle a été créé") messages.success(request, "Le modèle a été créé")
return redirect(reverse('topologie:index-model-switch')) return redirect(reverse('topologie:index-model-switch'))
return form({'topoform': model_switch, 'action_name' : 'Ajouter'}, 'topologie/topo.html', request) return form({'topoform': model_switch, 'action_name' : 'Ajouter'}, 'topologie/topo.html', request)
@ -724,13 +638,9 @@ def edit_model_switch(request, model_switch, modelswitchid):
model_switch = EditModelSwitchForm(request.POST or None, instance=model_switch) model_switch = EditModelSwitchForm(request.POST or None, instance=model_switch)
if model_switch.is_valid(): if model_switch.is_valid():
with transaction.atomic(), reversion.create_revision(): if model_switch.changed_data:
model_switch.save() model_switch.save()
reversion.set_user(request.user) messages.success(request, "Le modèle a bien été modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in model_switch.changed_data)
)
messages.success(request, "Le modèle a bien été modifié")
return redirect(reverse('topologie:index-model-switch')) return redirect(reverse('topologie:index-model-switch'))
return form({'topoform': model_switch, 'action_name' : 'Editer'}, 'topologie/topo.html', request) return form({'topoform': model_switch, 'action_name' : 'Editer'}, 'topologie/topo.html', request)
@ -741,11 +651,8 @@ def del_model_switch(request, model_switch, modelswitchid):
""" Suppression d'un modèle de switch""" """ Suppression d'un modèle de switch"""
if request.method == "POST": if request.method == "POST":
try: try:
with transaction.atomic(), reversion.create_revision(): model_switch.delete()
model_switch.delete() messages.success(request, "Le modèle a été détruit")
reversion.set_user(request.user)
reversion.set_comment("Destruction")
messages.success(request, "Le modèle a été détruit")
except ProtectedError: except ProtectedError:
messages.error(request, "Le modèle %s est affectée à un autre objet,\ messages.error(request, "Le modèle %s est affectée à un autre objet,\
impossible de la supprimer (switch ou user)" % model_switch) impossible de la supprimer (switch ou user)" % model_switch)
@ -762,10 +669,7 @@ def new_constructor_switch(request):
"""Nouveau constructeur de switch""" """Nouveau constructeur de switch"""
constructor_switch = EditConstructorSwitchForm(request.POST or None) constructor_switch = EditConstructorSwitchForm(request.POST or None)
if constructor_switch.is_valid(): if constructor_switch.is_valid():
with transaction.atomic(), reversion.create_revision(): constructor_switch.save()
constructor_switch.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Le constructeur a été créé") messages.success(request, "Le constructeur a été créé")
return redirect(reverse('topologie:index-model-switch')) return redirect(reverse('topologie:index-model-switch'))
return form({'topoform': constructor_switch, 'action_name' : 'Ajouter'}, 'topologie/topo.html', request) return form({'topoform': constructor_switch, 'action_name' : 'Ajouter'}, 'topologie/topo.html', request)
@ -778,13 +682,9 @@ def edit_constructor_switch(request, constructor_switch, constructorswitchid):
constructor_switch = EditConstructorSwitchForm(request.POST or None, instance=constructor_switch) constructor_switch = EditConstructorSwitchForm(request.POST or None, instance=constructor_switch)
if constructor_switch.is_valid(): if constructor_switch.is_valid():
with transaction.atomic(), reversion.create_revision(): if constructor_switch.changed_data:
constructor_switch.save() constructor_switch.save()
reversion.set_user(request.user) messages.success(request, "Le modèle a bien été modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in constructor_switch.changed_data)
)
messages.success(request, "Le modèle a bien été modifié")
return redirect(reverse('topologie:index-model-switch')) return redirect(reverse('topologie:index-model-switch'))
return form({'topoform': constructor_switch, 'action_name' : 'Editer'}, 'topologie/topo.html', request) return form({'topoform': constructor_switch, 'action_name' : 'Editer'}, 'topologie/topo.html', request)
@ -795,11 +695,8 @@ def del_constructor_switch(request, constructor_switch, constructorswitchid):
""" Suppression d'un constructeur de switch""" """ Suppression d'un constructeur de switch"""
if request.method == "POST": if request.method == "POST":
try: try:
with transaction.atomic(), reversion.create_revision(): constructor_switch.delete()
constructor_switch.delete() messages.success(request, "Le constructeur a été détruit")
reversion.set_user(request.user)
reversion.set_comment("Destruction")
messages.success(request, "Le constructeur a été détruit")
except ProtectedError: except ProtectedError:
messages.error(request, "Le constructeur %s est affecté à un autre objet,\ messages.error(request, "Le constructeur %s est affecté à un autre objet,\
impossible de la supprimer (switch ou user)" % constructor_switch) impossible de la supprimer (switch ou user)" % constructor_switch)

View file

@ -32,11 +32,28 @@ 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 reversion.admin import VersionAdmin
from .models import User, ServiceUser, School, ListRight, ListShell from .models import (
from .models import Ban, Whitelist, Request, LdapUser, LdapServiceUser User,
from .models import LdapServiceUserGroup, LdapUserGroup ServiceUser,
from .forms import UserChangeForm, UserCreationForm School,
from .forms import ServiceUserChangeForm, ServiceUserCreationForm ListRight,
ListShell,
Adherent,
Club,
Ban,
Whitelist,
Request,
LdapUser,
LdapServiceUser,
LdapServiceUserGroup,
LdapUserGroup
)
from .forms import (
UserChangeForm,
UserCreationForm,
ServiceUserChangeForm,
ServiceUserCreationForm
)
class UserAdmin(admin.ModelAdmin): class UserAdmin(admin.ModelAdmin):
@ -195,6 +212,8 @@ class ServiceUserAdmin(VersionAdmin, BaseUserAdmin):
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)
admin.site.register(Adherent, UserAdmin)
admin.site.register(Club, UserAdmin)
admin.site.register(ServiceUser, ServiceUserAdmin) admin.site.register(ServiceUser, ServiceUserAdmin)
admin.site.register(LdapUser, LdapUserAdmin) admin.site.register(LdapUser, LdapUserAdmin)
admin.site.register(LdapUserGroup, LdapUserGroupAdmin) admin.site.register(LdapUserGroup, LdapUserGroupAdmin)

View file

@ -53,13 +53,11 @@ from .models import (
Club Club
) )
from re2o.utils import remove_user_room from re2o.utils import remove_user_room
from re2o.mixins import FormRevMixin
from re2o.field_permissions import FieldPermissionFormMixin from re2o.field_permissions import FieldPermissionFormMixin
NOW = timezone.now()
class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm):
class PassForm(FieldPermissionFormMixin, forms.ModelForm):
"""Formulaire de changement de mot de passe. Verifie que les 2 """Formulaire de changement de mot de passe. Verifie que les 2
nouveaux mots de passe renseignés sont identiques et respectent nouveaux mots de passe renseignés sont identiques et respectent
une norme""" une norme"""
@ -107,7 +105,7 @@ class PassForm(FieldPermissionFormMixin, forms.ModelForm):
user.save() user.save()
class UserCreationForm(forms.ModelForm): class UserCreationForm(FormRevMixin, forms.ModelForm):
"""A form for creating new users. Includes all the required """A form for creating new users. Includes all the required
fields, plus a repeated password. fields, plus a repeated password.
@ -154,7 +152,7 @@ class UserCreationForm(forms.ModelForm):
return user return user
class ServiceUserCreationForm(forms.ModelForm): class ServiceUserCreationForm(FormRevMixin, forms.ModelForm):
"""A form for creating new users. Includes all the required """A form for creating new users. Includes all the required
fields, plus a repeated password. fields, plus a repeated password.
@ -202,7 +200,7 @@ class ServiceUserCreationForm(forms.ModelForm):
return user return user
class UserChangeForm(forms.ModelForm): class UserChangeForm(FormRevMixin, forms.ModelForm):
"""A form for updating users. Includes all the fields on """A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's the user, but replaces the password field with admin's
password hash display field. password hash display field.
@ -238,7 +236,7 @@ class UserChangeForm(forms.ModelForm):
return user return user
class ServiceUserChangeForm(forms.ModelForm): class ServiceUserChangeForm(FormRevMixin, forms.ModelForm):
"""A form for updating users. Includes all the fields on """A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's the user, but replaces the password field with admin's
password hash display field. password hash display field.
@ -281,12 +279,12 @@ class MassArchiveForm(forms.Form):
cleaned_data = super(MassArchiveForm, self).clean() cleaned_data = super(MassArchiveForm, self).clean()
date = cleaned_data.get("date") date = cleaned_data.get("date")
if date: if date:
if date > NOW: if date > timezone.now():
raise forms.ValidationError("Impossible d'archiver des\ raise forms.ValidationError("Impossible d'archiver des\
utilisateurs dont la fin d'accès se situe dans le futur !") utilisateurs dont la fin d'accès se situe dans le futur !")
class AdherentForm(FieldPermissionFormMixin, ModelForm): class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé """Formulaire de base d'edition d'un user. Formulaire de base, utilisé
pour l'edition de self par self ou un cableur. On formate les champs pour l'edition de self par self ou un cableur. On formate les champs
avec des label plus jolis""" avec des label plus jolis"""
@ -339,7 +337,7 @@ class AdherentForm(FieldPermissionFormMixin, ModelForm):
return return
class ClubForm(FieldPermissionFormMixin, ModelForm): class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé """Formulaire de base d'edition d'un user. Formulaire de base, utilisé
pour l'edition de self par self ou un cableur. On formate les champs pour l'edition de self par self ou un cableur. On formate les champs
avec des label plus jolis""" avec des label plus jolis"""
@ -379,7 +377,7 @@ class ClubForm(FieldPermissionFormMixin, ModelForm):
return telephone return telephone
class ClubAdminandMembersForm(ModelForm): class ClubAdminandMembersForm(FormRevMixin, ModelForm):
"""Permet d'éditer la liste des membres et des administrateurs """Permet d'éditer la liste des membres et des administrateurs
d'un club""" d'un club"""
class Meta: class Meta:
@ -391,7 +389,7 @@ class ClubAdminandMembersForm(ModelForm):
super(ClubAdminandMembersForm, self).__init__(*args, prefix=prefix, **kwargs) super(ClubAdminandMembersForm, self).__init__(*args, prefix=prefix, **kwargs)
class PasswordForm(ModelForm): class PasswordForm(FormRevMixin, ModelForm):
""" Formulaire de changement brut de mot de passe. """ Formulaire de changement brut de mot de passe.
Ne pas utiliser sans traitement""" Ne pas utiliser sans traitement"""
class Meta: class Meta:
@ -403,7 +401,7 @@ class PasswordForm(ModelForm):
super(PasswordForm, self).__init__(*args, prefix=prefix, **kwargs) super(PasswordForm, self).__init__(*args, prefix=prefix, **kwargs)
class ServiceUserForm(ModelForm): class ServiceUserForm(FormRevMixin, ModelForm):
""" Modification d'un service user""" """ Modification d'un service user"""
password = forms.CharField( password = forms.CharField(
label=u'Nouveau mot de passe', label=u'Nouveau mot de passe',
@ -429,7 +427,7 @@ class EditServiceUserForm(ServiceUserForm):
fields = ['access_group', 'comment'] fields = ['access_group', 'comment']
class StateForm(ModelForm): class StateForm(FormRevMixin, ModelForm):
""" Changement de l'état d'un user""" """ Changement de l'état d'un user"""
class Meta: class Meta:
model = User model = User
@ -440,7 +438,7 @@ class StateForm(ModelForm):
super(StateForm, self).__init__(*args, prefix=prefix, **kwargs) super(StateForm, self).__init__(*args, prefix=prefix, **kwargs)
class GroupForm(ModelForm): class GroupForm(FormRevMixin, ModelForm):
""" Gestion des groupes d'un user""" """ Gestion des groupes d'un user"""
groups = forms.ModelMultipleChoiceField( groups = forms.ModelMultipleChoiceField(
Group.objects.all(), Group.objects.all(),
@ -457,7 +455,7 @@ class GroupForm(ModelForm):
super(GroupForm, self).__init__(*args, prefix=prefix, **kwargs) super(GroupForm, self).__init__(*args, prefix=prefix, **kwargs)
class SchoolForm(ModelForm): class SchoolForm(FormRevMixin, ModelForm):
"""Edition, creation d'un école""" """Edition, creation d'un école"""
class Meta: class Meta:
model = School model = School
@ -469,7 +467,7 @@ class SchoolForm(ModelForm):
self.fields['name'].label = 'Établissement' self.fields['name'].label = 'Établissement'
class ShellForm(ModelForm): class ShellForm(FormRevMixin, ModelForm):
"""Edition, creation d'un école""" """Edition, creation d'un école"""
class Meta: class Meta:
model = ListShell model = ListShell
@ -481,7 +479,7 @@ class ShellForm(ModelForm):
self.fields['shell'].label = 'Nom du shell' self.fields['shell'].label = 'Nom du shell'
class ListRightForm(ModelForm): class ListRightForm(FormRevMixin, ModelForm):
"""Edition, d'un groupe , équivalent à un droit """Edition, d'un groupe , équivalent à un droit
Ne peremet pas d'editer le gid, car il sert de primary key""" Ne peremet pas d'editer le gid, car il sert de primary key"""
permissions = forms.ModelMultipleChoiceField( permissions = forms.ModelMultipleChoiceField(
@ -545,7 +543,7 @@ class DelSchoolForm(Form):
self.fields['schools'].queryset = School.objects.all() self.fields['schools'].queryset = School.objects.all()
class BanForm(ModelForm): class BanForm(FormRevMixin, ModelForm):
"""Creation, edition d'un objet bannissement""" """Creation, edition d'un objet bannissement"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
@ -557,7 +555,7 @@ class BanForm(ModelForm):
exclude = ['user'] exclude = ['user']
class WhitelistForm(ModelForm): class WhitelistForm(FormRevMixin, ModelForm):
"""Creation, edition d'un objet whitelist""" """Creation, edition d'un objet whitelist"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)

View file

@ -76,7 +76,7 @@ import ldapdb.models.fields
from re2o.settings import RIGHTS_LINK, LDAP, GID_RANGES, UID_RANGES from re2o.settings import RIGHTS_LINK, LDAP, GID_RANGES, UID_RANGES
from re2o.login import hashNT from re2o.login import hashNT
from re2o.field_permissions import FieldPermissionModelMixin from re2o.field_permissions import FieldPermissionModelMixin
from re2o.mixins import AclMixin from re2o.mixins import AclMixin, RevMixin
from cotisations.models import Cotisation, Facture, Paiement, Vente from cotisations.models import Cotisation, Facture, Paiement, Vente
from machines.models import Domain, Interface, Machine, regen from machines.models import Domain, Interface, Machine, regen
@ -171,7 +171,7 @@ class UserManager(BaseUserManager):
""" """
return self._create_user(pseudo, surname, email, password, True) return self._create_user(pseudo, surname, email, password, True)
class User(FieldPermissionModelMixin, AbstractBaseUser, PermissionsMixin, AclMixin): class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, PermissionsMixin, AclMixin):
""" Definition de l'utilisateur de base. """ Definition de l'utilisateur de base.
Champs principaux : name, surnname, pseudo, email, room, password Champs principaux : name, surnname, pseudo, email, room, password
Herite du django BaseUser et du système d'auth django""" Herite du django BaseUser et du système d'auth django"""
@ -548,15 +548,15 @@ class User(FieldPermissionModelMixin, AbstractBaseUser, PermissionsMixin, AclMix
'welcome_mail_en': mailmessageoptions.welcome_mail_en, 'welcome_mail_en': mailmessageoptions.welcome_mail_en,
'pseudo': self.pseudo, 'pseudo': self.pseudo,
}) })
send_mail( #send_mail(
'Bienvenue au %(name)s / Welcome to %(name)s' % { # 'Bienvenue au %(name)s / Welcome to %(name)s' % {
'name': AssoOption.get_cached_value('name') # 'name': AssoOption.get_cached_value('name')
}, # },
'', # '',
GeneralOption.get_cached_value('email_from'), # GeneralOption.get_cached_value('email_from'),
[self.email], # [self.email],
html_message=template.render(context) # html_message=template.render(context)
) #)
return return
def reset_passwd_mail(self, request): def reset_passwd_mail(self, request):
@ -576,14 +576,14 @@ class User(FieldPermissionModelMixin, AbstractBaseUser, PermissionsMixin, AclMix
reverse('users:process', kwargs={'token': req.token})), reverse('users:process', kwargs={'token': req.token})),
'expire_in': str(GeneralOption.get_cached_value('req_expire_hrs')) + ' heures', 'expire_in': str(GeneralOption.get_cached_value('req_expire_hrs')) + ' heures',
} }
send_mail( #send_mail(
'Changement de mot de passe du %(name)s / Password\ # 'Changement de mot de passe du %(name)s / Password\
renewal for %(name)s' % {'name': AssoOption.get_cached_value('name')}, # renewal for %(name)s' % {'name': AssoOption.get_cached_value('name')},
template.render(context), # template.render(context),
GeneralOption.get_cached_value('email_from'), # GeneralOption.get_cached_value('email_from'),
[req.user.email], # [req.user.email],
fail_silently=False # fail_silently=False
) #)
return return
def autoregister_machine(self, mac_address, nas_type): def autoregister_machine(self, mac_address, nas_type):
@ -892,8 +892,8 @@ def user_post_save(sender, **kwargs):
Synchronise le ldap""" Synchronise le ldap"""
is_created = kwargs['created'] is_created = kwargs['created']
user = kwargs['instance'] user = kwargs['instance']
if is_created: #if is_created:
user.notif_inscription() #user.notif_inscription()
user.ldap_sync(base=True, access_refresh=True, mac_refresh=False, group_refresh=True) user.ldap_sync(base=True, access_refresh=True, mac_refresh=False, group_refresh=True)
regen('mailing') regen('mailing')
@ -907,7 +907,7 @@ def user_post_delete(sender, **kwargs):
user.ldap_del() user.ldap_del()
regen('mailing') regen('mailing')
class ServiceUser(AclMixin, AbstractBaseUser): class ServiceUser(RevMixin, AclMixin, AbstractBaseUser):
""" Classe des users daemons, règle leurs accès au ldap""" """ Classe des users daemons, règle leurs accès au ldap"""
readonly = 'readonly' readonly = 'readonly'
ACCESS = ( ACCESS = (
@ -991,7 +991,7 @@ def service_user_post_delete(sender, **kwargs):
service_user.ldap_del() service_user.ldap_del()
class School(AclMixin, models.Model): class School(RevMixin, AclMixin, models.Model):
""" Etablissement d'enseignement""" """ Etablissement d'enseignement"""
PRETTY_NAME = "Établissements enregistrés" PRETTY_NAME = "Établissements enregistrés"
@ -1006,7 +1006,7 @@ class School(AclMixin, models.Model):
return self.name return self.name
class ListRight(AclMixin, Group): class ListRight(RevMixin, AclMixin, Group):
""" Ensemble des droits existants. Chaque droit crée un groupe """ Ensemble des droits existants. Chaque droit crée un groupe
ldap synchronisé, avec gid. ldap synchronisé, avec gid.
Permet de gérer facilement les accès serveurs et autres Permet de gérer facilement les accès serveurs et autres
@ -1073,7 +1073,7 @@ def listright_post_delete(sender, **kwargs):
right.ldap_del() right.ldap_del()
class ListShell(AclMixin, models.Model): class ListShell(RevMixin, AclMixin, models.Model):
"""Un shell possible. Pas de check si ce shell existe, les """Un shell possible. Pas de check si ce shell existe, les
admin sont des grands""" admin sont des grands"""
PRETTY_NAME = "Liste des shells disponibles" PRETTY_NAME = "Liste des shells disponibles"
@ -1093,7 +1093,7 @@ class ListShell(AclMixin, models.Model):
return self.shell return self.shell
class Ban(AclMixin, models.Model): class Ban(RevMixin, AclMixin, models.Model):
""" Bannissement. Actuellement a un effet tout ou rien. """ Bannissement. Actuellement a un effet tout ou rien.
Gagnerait à être granulaire""" Gagnerait à être granulaire"""
PRETTY_NAME = "Liste des bannissements" PRETTY_NAME = "Liste des bannissements"
@ -1127,22 +1127,19 @@ class Ban(AclMixin, models.Model):
'date_end': self.date_end, 'date_end': self.date_end,
'asso_name': AssoOption.get_cached_value('name'), 'asso_name': AssoOption.get_cached_value('name'),
}) })
send_mail( #send_mail(
'Deconnexion disciplinaire', # 'Deconnexion disciplinaire',
template.render(context), # template.render(context),
GeneralOption.get_cached_value('email_from'), # GeneralOption.get_cached_value('email_from'),
[self.user.email], # [self.user.email],
fail_silently=False # fail_silently=False
) #)
return return
def is_active(self): def is_active(self):
"""Ce ban est-il actif?""" """Ce ban est-il actif?"""
return self.date_end > timezone.now() return self.date_end > timezone.now()
def get_instance(banid, *args, **kwargs):
return Ban.objects.get(pk=banid)
def can_view(self, user_request, *args, **kwargs): def can_view(self, user_request, *args, **kwargs):
"""Check if an user can view a Ban object. """Check if an user can view a Ban object.
@ -1189,7 +1186,7 @@ def ban_post_delete(sender, **kwargs):
regen('mac_ip_list') regen('mac_ip_list')
class Whitelist(AclMixin, models.Model): class Whitelist(RevMixin, AclMixin, models.Model):
"""Accès à titre gracieux. L'utilisateur ne paye pas; se voit """Accès à titre gracieux. L'utilisateur ne paye pas; se voit
accorder un accès internet pour une durée défini. Moins accorder un accès internet pour une durée défini. Moins
fort qu'un ban quel qu'il soit""" fort qu'un ban quel qu'il soit"""

View file

@ -39,7 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% can_edit shell %} {% can_edit shell %}
{% include 'buttons/edit.html' with href='users:edit-shell' id=shell.id %} {% include 'buttons/edit.html' with href='users:edit-shell' id=shell.id %}
{% acl_end %} {% acl_end %}
{% include 'buttons/history.html' with href='users:history' name='shell' id=shell.id %} {% include 'buttons/history.html' with href='users:history' name='listshell' id=shell.id %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -115,10 +115,7 @@ def new_user(request):
GTU = GeneralOption.get_cached_value('GTU') GTU = GeneralOption.get_cached_value('GTU')
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")
user.reset_passwd_mail(request) user.reset_passwd_mail(request)
messages.success(request, "L'utilisateur %s a été crée, un mail\ messages.success(request, "L'utilisateur %s a été crée, un mail\
pour l'initialisation du mot de passe a été envoyé" % user.pseudo) pour l'initialisation du mot de passe a été envoyé" % user.pseudo)
@ -137,10 +134,7 @@ def new_club(request):
club = ClubForm(request.POST or None, user=request.user) club = ClubForm(request.POST or None, user=request.user)
if club.is_valid(): if club.is_valid():
club = club.save(commit=False) club = club.save(commit=False)
with transaction.atomic(), reversion.create_revision(): club.save()
club.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
club.reset_passwd_mail(request) club.reset_passwd_mail(request)
messages.success(request, "L'utilisateur %s a été crée, un mail\ messages.success(request, "L'utilisateur %s a été crée, un mail\
pour l'initialisation du mot de passe a été envoyé" % club.pseudo) pour l'initialisation du mot de passe a été envoyé" % club.pseudo)
@ -158,13 +152,9 @@ def edit_club_admin_members(request, club_instance, clubid):
membres d'un club""" membres d'un club"""
club = ClubAdminandMembersForm(request.POST or None, instance=club_instance) club = ClubAdminandMembersForm(request.POST or None, instance=club_instance)
if club.is_valid(): if club.is_valid():
with transaction.atomic(), reversion.create_revision(): if club.changed_data:
club.save() club.save()
reversion.set_user(request.user) messages.success(request, "Le club a bien été modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in club.changed_data
))
messages.success(request, "Le club a bien été modifié")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid':str(club_instance.id)} kwargs={'userid':str(club_instance.id)}
@ -191,13 +181,9 @@ def edit_info(request, user, userid):
user=request.user user=request.user
) )
if user.is_valid(): if user.is_valid():
with transaction.atomic(), reversion.create_revision(): if user.changed_data:
user.save() user.save()
reversion.set_user(request.user) messages.success(request, "L'user a bien été modifié")
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(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid':str(userid)} kwargs={'userid':str(userid)}
@ -212,19 +198,15 @@ def state(request, user, userid):
need droit bureau """ need droit bureau """
state = StateForm(request.POST or None, instance=user) state = StateForm(request.POST or None, instance=user)
if state.is_valid(): if state.is_valid():
with transaction.atomic(), reversion.create_revision(): if state.cleaned_data['state'] == User.STATE_ARCHIVE:
if state.cleaned_data['state'] == User.STATE_ARCHIVE: user.archive()
user.archive() elif state.cleaned_data['state'] == User.STATE_ACTIVE:
elif state.cleaned_data['state'] == User.STATE_ACTIVE: user.unarchive()
user.unarchive() elif state.cleaned_data['state'] == User.STATE_DISABLED:
elif state.cleaned_data['state'] == User.STATE_DISABLED: user.state = User.STATE_DISABLED
user.state = User.STATE_DISABLED if user.changed_data:
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in state.changed_data
))
user.save() user.save()
messages.success(request, "Etat changé avec succès") messages.success(request, "Etat changé avec succès")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid':str(userid)} kwargs={'userid':str(userid)}
@ -237,13 +219,9 @@ def state(request, user, userid):
def groups(request, user, userid): def groups(request, user, userid):
group = GroupForm(request.POST or None, instance=user) group = GroupForm(request.POST or None, instance=user)
if group.is_valid(): if group.is_valid():
with transaction.atomic(), reversion.create_revision(): if group.changed_data:
reversion.set_user(request.user) group.save()
reversion.set_comment("Champs modifié(s) : %s" % ', '.join( messages.success(request, "Groupes changés avec succès")
field for field in group.changed_data
))
group.save()
messages.success(request, "Groupes changés avec succès")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid':str(userid)} kwargs={'userid':str(userid)}
@ -259,11 +237,9 @@ def password(request, user, userid):
pour tous si droit bureau """ pour tous si droit bureau """
u_form = PassForm(request.POST or None, instance=user, user=request.user) u_form = PassForm(request.POST or None, instance=user, user=request.user)
if u_form.is_valid(): if u_form.is_valid():
with transaction.atomic(), reversion.create_revision(): if u_form.changed_data:
u_form.save() u_form.save()
reversion.set_user(request.user) messages.success(request, "Le mot de passe a changé")
reversion.set_comment("Changement du mot de passe")
messages.success(request, "Le mot de passe a changé")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid':str(user.id)} kwargs={'userid':str(user.id)}
@ -274,12 +250,9 @@ def password(request, user, userid):
@login_required @login_required
@can_edit(User, 'groups') @can_edit(User, 'groups')
def del_group(request, user, userid, listrightid): def del_group(request, user, userid, listrightid):
with transaction.atomic(), reversion.create_revision(): user.groups.remove(ListRight.objects.get(id=listrightid))
user.groups.remove(ListRight.objects.get(id=listrightid)) user.save()
user.save() messages.success(request, "Droit supprimé à %s" % user)
reversion.set_user(request.user)
reversion.set_comment("Suppression de droit")
messages.success(request, "Droit supprimé à %s" % user)
return HttpResponseRedirect(request.META.get('HTTP_REFERER')) return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
@ -290,11 +263,8 @@ def new_serviceuser(request):
user = ServiceUserForm(request.POST or None) user = ServiceUserForm(request.POST or None)
if user.is_valid(): if user.is_valid():
user_object = user.save(commit=False) user_object = user.save(commit=False)
with transaction.atomic(), reversion.create_revision(): user_object.set_password(user.cleaned_data['password'])
user_object.set_password(user.cleaned_data['password']) user_object.save()
user_object.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success( messages.success(
request, request,
"L'utilisateur %s a été crée" % user_object.pseudo "L'utilisateur %s a été crée" % user_object.pseudo
@ -310,14 +280,10 @@ def edit_serviceuser(request, user, userid):
user = EditServiceUserForm(request.POST or None, instance=user) user = EditServiceUserForm(request.POST or None, instance=user)
if user.is_valid(): if user.is_valid():
user_object = user.save(commit=False) user_object = user.save(commit=False)
with transaction.atomic(), reversion.create_revision(): if user.cleaned_data['password']:
if user.cleaned_data['password']: user_object.set_password(user.cleaned_data['password'])
user_object.set_password(user.cleaned_data['password']) if user.changed_data:
user_object.save() user_object.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(reverse('users:index-serviceusers')) return redirect(reverse('users:index-serviceusers'))
return form({'userform': user, 'action_name':'Editer un serviceuser'}, 'users/user.html', request) return form({'userform': user, 'action_name':'Editer un serviceuser'}, 'users/user.html', request)
@ -328,9 +294,7 @@ def edit_serviceuser(request, user, userid):
def del_serviceuser(request, user, userid): def del_serviceuser(request, user, userid):
"""Suppression d'un ou plusieurs serviceusers""" """Suppression d'un ou plusieurs serviceusers"""
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision(): user.delete()
user.delete()
reversion.set_user(request.user)
messages.success(request, "L'user a été détruite") messages.success(request, "L'user a été détruite")
return redirect(reverse('users:index-serviceusers')) return redirect(reverse('users:index-serviceusers'))
return form( return form(
@ -350,10 +314,7 @@ def add_ban(request, user, 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_object = ban.save()
_ban_object = ban.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Bannissement ajouté") messages.success(request, "Bannissement ajouté")
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
@ -374,13 +335,9 @@ def edit_ban(request, ban_instance, banid):
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement""" Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement"""
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(): if ban.changed_data:
ban.save() ban.save()
reversion.set_user(request.user) messages.success(request, "Bannissement modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in ban.changed_data
))
messages.success(request, "Bannissement modifié")
return redirect(reverse('users:index')) return redirect(reverse('users:index'))
return form({'userform': ban, 'action_name': 'Editer un ban'}, 'users/user.html', request) return form({'userform': ban, 'action_name': 'Editer un ban'}, 'users/user.html', request)
@ -399,10 +356,7 @@ def add_whitelist(request, user, userid):
instance=whitelist_instance 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(reverse( return redirect(reverse(
'users:profil', 'users:profil',
@ -428,13 +382,9 @@ def edit_whitelist(request, whitelist_instance, whitelistid):
instance=whitelist_instance instance=whitelist_instance
) )
if whitelist.is_valid(): if whitelist.is_valid():
with transaction.atomic(), reversion.create_revision(): if whitelist.changed_data:
whitelist.save() whitelist.save()
reversion.set_user(request.user) messages.success(request, "Whitelist modifiée")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in whitelist.changed_data
))
messages.success(request, "Whitelist modifiée")
return redirect(reverse('users:index')) return redirect(reverse('users:index'))
return form({'userform': whitelist, 'action_name': 'Editer une whitelist'}, 'users/user.html', request) return form({'userform': whitelist, 'action_name': 'Editer une whitelist'}, 'users/user.html', request)
@ -446,10 +396,7 @@ def add_school(request):
need cableur""" need cableur"""
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(reverse('users:index-school')) return redirect(reverse('users:index-school'))
return form({'userform': school, 'action_name':'Ajouter'}, 'users/user.html', request) return form({'userform': school, 'action_name':'Ajouter'}, 'users/user.html', request)
@ -462,13 +409,9 @@ def edit_school(request, school_instance, schoolid):
la base de donnée, need cableur""" la base de donnée, need cableur"""
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(): if school.changed_data:
school.save() school.save()
reversion.set_user(request.user) messages.success(request, "Établissement modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in school.changed_data
))
messages.success(request, "Établissement modifié")
return redirect(reverse('users:index-school')) return redirect(reverse('users:index-school'))
return form({'userform': school, 'action_name':'Editer'}, 'users/user.html', request) return form({'userform': school, 'action_name':'Editer'}, 'users/user.html', request)
@ -485,9 +428,7 @@ def del_school(request, instances):
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(
@ -504,10 +445,7 @@ def add_shell(request):
""" Ajouter un shell à la base de donnée""" """ Ajouter un shell à la base de donnée"""
shell = ShellForm(request.POST or None) shell = ShellForm(request.POST or None)
if shell.is_valid(): if shell.is_valid():
with transaction.atomic(), reversion.create_revision(): shell.save()
shell.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Le shell a été ajouté") messages.success(request, "Le shell a été ajouté")
return redirect(reverse('users:index-shell')) return redirect(reverse('users:index-shell'))
return form({'userform': shell, 'action_name':'Ajouter'}, 'users/user.html', request) return form({'userform': shell, 'action_name':'Ajouter'}, 'users/user.html', request)
@ -519,13 +457,9 @@ def edit_shell(request, shell_instance, listshellid):
""" Editer un shell à partir du listshellid""" """ Editer un shell à partir du listshellid"""
shell = ShellForm(request.POST or None, instance=shell_instance) shell = ShellForm(request.POST or None, instance=shell_instance)
if shell.is_valid(): if shell.is_valid():
with transaction.atomic(), reversion.create_revision(): if shell.changed_data:
shell.save() shell.save()
reversion.set_user(request.user) messages.success(request, "Le shell a été modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in shell.changed_data
))
messages.success(request, "Le shell a été modifié")
return redirect(reverse('users:index-shell')) return redirect(reverse('users:index-shell'))
return form({'userform': shell, 'action_name':'Editer'}, 'users/user.html', request) return form({'userform': shell, 'action_name':'Editer'}, 'users/user.html', request)
@ -535,9 +469,7 @@ def edit_shell(request, shell_instance, listshellid):
def del_shell(request, shell, listshellid): def del_shell(request, shell, listshellid):
"""Destruction d'un shell""" """Destruction d'un shell"""
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision(): shell.delete()
shell.delete()
reversion.set_user(request.user)
messages.success(request, "Le shell a été détruit") messages.success(request, "Le shell a été détruit")
return redirect(reverse('users:index-shell')) return redirect(reverse('users:index-shell'))
return form( return form(
@ -554,10 +486,7 @@ def add_listright(request):
Obligation de fournir un gid pour la synchro ldap, unique """ Obligation de fournir un gid pour la synchro ldap, unique """
listright = NewListRightForm(request.POST or None) listright = NewListRightForm(request.POST or None)
if listright.is_valid(): if listright.is_valid():
with transaction.atomic(), reversion.create_revision(): listright.save()
listright.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Le droit/groupe a été ajouté") messages.success(request, "Le droit/groupe a été ajouté")
return redirect(reverse('users:index-listright')) return redirect(reverse('users:index-listright'))
return form({'userform': listright, 'action_name': 'Ajouter'}, 'users/user.html', request) return form({'userform': listright, 'action_name': 'Ajouter'}, 'users/user.html', request)
@ -573,13 +502,9 @@ def edit_listright(request, listright_instance, listrightid):
instance=listright_instance instance=listright_instance
) )
if listright.is_valid(): if listright.is_valid():
with transaction.atomic(), reversion.create_revision(): if listright.changed_data:
listright.save() listright.save()
reversion.set_user(request.user) messages.success(request, "Droit modifié")
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in listright.changed_data
))
messages.success(request, "Droit modifié")
return redirect(reverse('users:index-listright')) return redirect(reverse('users:index-listright'))
return form({'userform': listright, 'action_name': 'Editer'}, 'users/user.html', request) return form({'userform': listright, 'action_name': 'Editer'}, 'users/user.html', request)
@ -594,9 +519,7 @@ def del_listright(request, instances):
listright_dels = listright.cleaned_data['listrights'] listright_dels = listright.cleaned_data['listrights']
for listright_del in listright_dels: for listright_del in listright_dels:
try: try:
with transaction.atomic(), reversion.create_revision(): listright_del.delete()
listright_del.delete()
reversion.set_comment("Destruction")
messages.success(request, "Le droit/groupe a été supprimé") messages.success(request, "Le droit/groupe a été supprimé")
except ProtectedError: except ProtectedError:
messages.error( messages.error(
@ -625,7 +548,6 @@ def mass_archive(request):
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
user.archive() user.archive()
user.save() user.save()
reversion.set_user(request.user)
reversion.set_comment("Archivage") reversion.set_comment("Archivage")
messages.success(request, "%s users ont été archivés" % len( messages.success(request, "%s users ont été archivés" % len(
to_archive_list to_archive_list