Commit 4c0d9b9a authored by chirac's avatar chirac

Pep8 et nettoyage, et doc pour l'app preferences

parent 6cac4b20
......@@ -20,35 +20,53 @@
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Classes admin pour les models de preferences
"""
from __future__ import unicode_literals
from django.contrib import admin
from reversion.admin import VersionAdmin
from .models import OptionalUser, OptionalMachine, OptionalTopologie, GeneralOption, Service, AssoOption, MailMessageOption
from .models import OptionalUser, OptionalMachine, OptionalTopologie
from .models import GeneralOption, Service, AssoOption, MailMessageOption
class OptionalUserAdmin(VersionAdmin):
"""Class admin options user"""
pass
class OptionalTopologieAdmin(VersionAdmin):
"""Class admin options topologie"""
pass
class OptionalMachineAdmin(VersionAdmin):
"""Class admin options machines"""
pass
class GeneralOptionAdmin(VersionAdmin):
"""Class admin options générales"""
pass
class ServiceAdmin(VersionAdmin):
"""Class admin gestion des services de la page d'accueil"""
pass
class AssoOptionAdmin(VersionAdmin):
"""Class admin options de l'asso"""
pass
class MailMessageOptionAdmin(VersionAdmin):
"""Class admin options mail"""
pass
admin.site.register(OptionalUser, OptionalUserAdmin)
admin.site.register(OptionalMachine, OptionalMachineAdmin)
admin.site.register(OptionalTopologie, OptionalTopologieAdmin)
......
......@@ -19,71 +19,116 @@
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Formulaire d'edition des réglages : user, machine, topologie, asso...
"""
from __future__ import unicode_literals
from django.forms import ModelForm, Form, ValidationError
from django.forms import ModelForm, Form
from django import forms
from .models import OptionalUser, OptionalMachine, OptionalTopologie, GeneralOption, AssoOption, MailMessageOption, Service
from django.db.models import Q
from .models import OptionalUser, OptionalMachine, OptionalTopologie
from .models import GeneralOption, AssoOption, MailMessageOption, Service
class EditOptionalUserForm(ModelForm):
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
class Meta:
model = OptionalUser
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditOptionalUserForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['is_tel_mandatory'].label = 'Exiger un numéro de téléphone'
self.fields['user_solde'].label = 'Activation du solde pour les utilisateurs'
super(EditOptionalUserForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
self.fields['is_tel_mandatory'].label = 'Exiger un numéro de\
téléphone'
self.fields['user_solde'].label = 'Activation du solde pour\
les utilisateurs'
class EditOptionalMachineForm(ModelForm):
"""Options machines (max de machines, etc)"""
class Meta:
model = OptionalMachine
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditOptionalMachineForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['password_machine'].label = "Possibilité d'attribuer un mot de passe par interface"
self.fields['max_lambdauser_interfaces'].label = "Maximum d'interfaces autorisées pour un user normal"
self.fields['max_lambdauser_aliases'].label = "Maximum d'alias dns autorisés pour un user normal"
super(EditOptionalMachineForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
self.fields['password_machine'].label = "Possibilité d'attribuer\
un mot de passe par interface"
self.fields['max_lambdauser_interfaces'].label = "Maximum\
d'interfaces autorisées pour un user normal"
self.fields['max_lambdauser_aliases'].label = "Maximum d'alias\
dns autorisés pour un user normal"
class EditOptionalTopologieForm(ModelForm):
"""Options de topologie, formulaire d'edition (vlan par default etc)"""
class Meta:
model = OptionalTopologie
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditOptionalTopologieForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['vlan_decision_ok'].label = "Vlan où placer les machines après acceptation RADIUS"
self.fields['vlan_decision_nok'].label = "Vlan où placer les machines après rejet RADIUS"
super(EditOptionalTopologieForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
self.fields['vlan_decision_ok'].label = "Vlan où placer les\
machines après acceptation RADIUS"
self.fields['vlan_decision_nok'].label = "Vlan où placer les\
machines après rejet RADIUS"
class EditGeneralOptionForm(ModelForm):
"""Options générales (affichages de résultats de recherche, etc)"""
class Meta:
model = GeneralOption
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditGeneralOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['search_display_page'].label = 'Resultats affichés dans une recherche'
self.fields['pagination_number'].label = 'Items par page, taille normale (ex users)'
self.fields['pagination_large_number'].label = 'Items par page, taille élevée (machines)'
self.fields['req_expire_hrs'].label = 'Temps avant expiration du lien de reinitialisation de mot de passe (en heures)'
super(EditGeneralOptionForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
self.fields['search_display_page'].label = 'Resultats\
affichés dans une recherche'
self.fields['pagination_number'].label = 'Items par page,\
taille normale (ex users)'
self.fields['pagination_large_number'].label = 'Items par page,\
taille élevée (machines)'
self.fields['req_expire_hrs'].label = 'Temps avant expiration du lien\
de reinitialisation de mot de passe (en heures)'
self.fields['site_name'].label = 'Nom du site web'
self.fields['email_from'].label = 'Adresse mail d\'expedition automatique'
self.fields['email_from'].label = "Adresse mail d\
'expedition automatique"
class EditAssoOptionForm(ModelForm):
"""Options de l'asso (addresse, telephone, etc)"""
class Meta:
model = AssoOption
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditAssoOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
super(EditAssoOptionForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
self.fields['name'].label = 'Nom de l\'asso'
self.fields['siret'].label = 'SIRET'
self.fields['adresse1'].label = 'Adresse (ligne 1)'
......@@ -91,20 +136,31 @@ class EditAssoOptionForm(ModelForm):
self.fields['contact'].label = 'Email de contact'
self.fields['telephone'].label = 'Numéro de téléphone'
self.fields['pseudo'].label = 'Pseudo d\'usage'
self.fields['utilisateur_asso'].label = 'Compte utilisé pour faire les modifications depuis /admin'
self.fields['utilisateur_asso'].label = 'Compte utilisé pour\
faire les modifications depuis /admin'
class EditMailMessageOptionForm(ModelForm):
"""Formulaire d'edition des messages de bienvenue personnalisés"""
class Meta:
model = MailMessageOption
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditMailMessageOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['welcome_mail_fr'].label = 'Message dans le mail de bienvenue en français'
self.fields['welcome_mail_en'].label = 'Message dans le mail de bienvenue en anglais'
super(EditMailMessageOptionForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
self.fields['welcome_mail_fr'].label = 'Message dans le\
mail de bienvenue en français'
self.fields['welcome_mail_en'].label = 'Message dans le\
mail de bienvenue en anglais'
class ServiceForm(ModelForm):
"""Edition, ajout de services sur la page d'accueil"""
class Meta:
model = Service
fields = '__all__'
......@@ -113,6 +169,11 @@ class ServiceForm(ModelForm):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelServiceForm(Form):
services = forms.ModelMultipleChoiceField(queryset=Service.objects.all(), label="Enregistrements service actuels", widget=forms.CheckboxSelectMultiple)
class DelServiceForm(Form):
"""Suppression de services sur la page d'accueil"""
services = forms.ModelMultipleChoiceField(
queryset=Service.objects.all(),
label="Enregistrements service actuels",
widget=forms.CheckboxSelectMultiple
)
......@@ -20,26 +20,38 @@
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Reglages généraux, machines, utilisateurs, mail, general pour l'application.
"""
from __future__ import unicode_literals
from django.db import models
from cotisations.models import Paiement
from machines.models import Vlan
class OptionalUser(models.Model):
"""Options pour l'user : obligation ou nom du telephone,
activation ou non du solde, autorisation du negatif, fingerprint etc"""
PRETTY_NAME = "Options utilisateur"
is_tel_mandatory = models.BooleanField(default=True)
user_solde = models.BooleanField(default=False)
solde_negatif = models.DecimalField(max_digits=5, decimal_places=2, default=0)
solde_negatif = models.DecimalField(
max_digits=5,
decimal_places=2,
default=0
)
gpg_fingerprint = models.BooleanField(default=True)
def clean(self):
"""Creation du mode de paiement par solde"""
if self.user_solde:
Paiement.objects.get_or_create(moyen="Solde")
class OptionalMachine(models.Model):
"""Options pour les machines : maximum de machines ou d'alias par user
sans droit, activation de l'ipv6"""
PRETTY_NAME = "Options machines"
password_machine = models.BooleanField(default=False)
......@@ -47,21 +59,43 @@ class OptionalMachine(models.Model):
max_lambdauser_aliases = models.IntegerField(default=10)
ipv6 = models.BooleanField(default=False)
class OptionalTopologie(models.Model):
"""Reglages pour la topologie : mode d'accès radius, vlan où placer
les machines en accept ou reject"""
PRETTY_NAME = "Options topologie"
MACHINE = 'MACHINE'
DEFINED = 'DEFINED'
CHOICE_RADIUS = (
(MACHINE, 'Sur le vlan de la plage ip machine'),
(DEFINED, 'Prédéfini dans "Vlan où placer les machines après acceptation RADIUS"'),
(MACHINE, 'Sur le vlan de la plage ip machine'),
(DEFINED, 'Prédéfini dans "Vlan où placer les machines\
après acceptation RADIUS"'),
)
radius_general_policy = models.CharField(
max_length=32,
choices=CHOICE_RADIUS,
default='DEFINED'
)
vlan_decision_ok = models.OneToOneField(
'machines.Vlan',
on_delete=models.PROTECT,
related_name='decision_ok',
blank=True,
null=True
)
vlan_decision_nok = models.OneToOneField(
'machines.Vlan',
on_delete=models.PROTECT,
related_name='decision_nok',
blank=True,
null=True
)
radius_general_policy = models.CharField(max_length=32, choices=CHOICE_RADIUS, default='DEFINED')
vlan_decision_ok = models.OneToOneField('machines.Vlan', on_delete=models.PROTECT, related_name='decision_ok', blank=True, null=True)
vlan_decision_nok = models.OneToOneField('machines.Vlan', on_delete=models.PROTECT, related_name='decision_nok', blank=True, null=True)
class GeneralOption(models.Model):
"""Options générales : nombre de resultats par page, nom du site,
temps où les liens sont valides"""
PRETTY_NAME = "Options générales"
search_display_page = models.IntegerField(default=15)
......@@ -71,30 +105,44 @@ class GeneralOption(models.Model):
site_name = models.CharField(max_length=32, default="Re2o")
email_from = models.EmailField(default="www-data@serveur.net")
class Service(models.Model):
"""Liste des services affichés sur la page d'accueil : url, description,
image et nom"""
name = models.CharField(max_length=32)
url = models.URLField()
description = models.TextField()
image = models.ImageField(upload_to='logo', blank=True)
image = models.ImageField(upload_to='logo', blank=True)
def __str__(self):
return str(self.name)
class AssoOption(models.Model):
"""Options générales de l'asso : siret, addresse, nom, etc"""
PRETTY_NAME = "Options de l'association"
name = models.CharField(default="Association réseau école machin", max_length=256)
name = models.CharField(
default="Association réseau école machin",
max_length=256
)
siret = models.CharField(default="00000000000000", max_length=32)
adresse1 = models.CharField(default="1 Rue de exemple", max_length=128)
adresse2 = models.CharField(default="94230 Cachan", max_length=128)
contact = models.EmailField(default="contact@example.org")
telephone = models.CharField(max_length=15, default="0000000000")
pseudo = models.CharField(default="Asso", max_length=32)
utilisateur_asso = models.OneToOneField('users.User', on_delete=models.PROTECT, blank=True, null=True)
utilisateur_asso = models.OneToOneField(
'users.User',
on_delete=models.PROTECT,
blank=True,
null=True
)
class MailMessageOption(models.Model):
"""Reglages, mail de bienvenue et autre"""
PRETTY_NAME = "Options de corps de mail"
welcome_mail_fr = models.TextField(default="")
welcome_mail_en = models.TextField(default="")
......@@ -19,6 +19,9 @@
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Urls de l'application preferences, pointant vers les fonctions de views
"""
from __future__ import unicode_literals
......@@ -28,15 +31,47 @@ from . import views
urlpatterns = [
url(r'^edit_options/(?P<section>OptionalUser)$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>OptionalMachine)$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>OptionalTopologie)$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>GeneralOption)$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>AssoOption)$', views.edit_options, name='edit-options'),
url(r'^edit_options/(?P<section>MailMessageOption)$', views.edit_options, name='edit-options'),
url(
r'^edit_options/(?P<section>OptionalUser)$',
views.edit_options,
name='edit-options'
),
url(
r'^edit_options/(?P<section>OptionalMachine)$',
views.edit_options,
name='edit-options'
),
url(
r'^edit_options/(?P<section>OptionalTopologie)$',
views.edit_options,
name='edit-options'
),
url(
r'^edit_options/(?P<section>GeneralOption)$',
views.edit_options,
name='edit-options'
),
url(
r'^edit_options/(?P<section>AssoOption)$',
views.edit_options,
name='edit-options'
),
url(
r'^edit_options/(?P<section>MailMessageOption)$',
views.edit_options,
name='edit-options'
),
url(r'^add_services/$', views.add_services, name='add-services'),
url(r'^edit_services/(?P<servicesid>[0-9]+)$', views.edit_services, name='edit-services'),
url(
r'^edit_services/(?P<servicesid>[0-9]+)$',
views.edit_services,
name='edit-services'
),
url(r'^del_services/$', views.del_services, name='del-services'),
url(r'^history/(?P<object>service)/(?P<id>[0-9]+)$', views.history, name='history'),
url(
r'^history/(?P<object>service)/(?P<id>[0-9]+)$',
views.history,
name='history'
),
url(r'^$', views.display_options, name='display-options'),
]
......@@ -23,48 +23,53 @@
# App de gestion des machines pour re2o
# Gabriel Détraz, Augustin Lemesle
# Gplv2
"""
Vue d'affichage, et de modification des réglages (réglages machine,
topologie, users, service...)
"""
from __future__ import unicode_literals
from django.shortcuts import render
from django.shortcuts import get_object_or_404, render, redirect
from django.template.context_processors import csrf
from django.shortcuts import render, redirect
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.template import Context, RequestContext, loader
from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.db.models import Max, ProtectedError
from django.db import IntegrityError
from django.core.mail import send_mail
from django.utils import timezone
from django.core.urlresolvers import reverse
from django.db.models import ProtectedError
from django.db import transaction
from reversion.models import Version
from reversion import revisions as reversion
from re2o.views import form
from .forms import ServiceForm, DelServiceForm
from .models import Service, OptionalUser, OptionalMachine, AssoOption, MailMessageOption, GeneralOption, OptionalTopologie
from .models import Service, OptionalUser, OptionalMachine, AssoOption
from .models import MailMessageOption, GeneralOption, OptionalTopologie
from . import models
from . import forms
def form(ctx, template, request):
c = ctx
c.update(csrf(request))
return render(request, template, c)
@login_required
@permission_required('cableur')
def display_options(request):
useroptions, created = OptionalUser.objects.get_or_create()
machineoptions, created = OptionalMachine.objects.get_or_create()
topologieoptions, created = OptionalTopologie.objects.get_or_create()
generaloptions, created = GeneralOption.objects.get_or_create()
assooptions, created = AssoOption.objects.get_or_create()
mailmessageoptions, created = MailMessageOption.objects.get_or_create()
"""Vue pour affichage des options (en vrac) classé selon les models
correspondants dans un tableau"""
useroptions, _created = OptionalUser.objects.get_or_create()
machineoptions, _created = OptionalMachine.objects.get_or_create()
topologieoptions, _created = OptionalTopologie.objects.get_or_create()
generaloptions, _created = GeneralOption.objects.get_or_create()
assooptions, _created = AssoOption.objects.get_or_create()
mailmessageoptions, _created = MailMessageOption.objects.get_or_create()
service_list = Service.objects.all()
return form({'useroptions': useroptions, 'machineoptions': machineoptions, 'topologieoptions': topologieoptions, 'generaloptions': generaloptions, 'assooptions' : assooptions, 'mailmessageoptions' : mailmessageoptions, 'service_list':service_list}, 'preferences/display_preferences.html', request)
return form({
'useroptions': useroptions,
'machineoptions': machineoptions,
'topologieoptions': topologieoptions,
'generaloptions': generaloptions,
'assooptions': assooptions,
'mailmessageoptions': mailmessageoptions,
'service_list': service_list
}, 'preferences/display_preferences.html', request)
@login_required
@permission_required('admin')
......@@ -73,23 +78,36 @@ def edit_options(request, section):
model = getattr(models, section, None)
form_instance = getattr(forms, 'Edit' + section + 'Form', None)
if model and form:
options_instance, created = model.objects.get_or_create()
options = form_instance(request.POST or None, instance=options_instance)
options_instance, _created = model.objects.get_or_create()
options = form_instance(
request.POST or None,
instance=options_instance
)
if options.is_valid():
with transaction.atomic(), reversion.create_revision():
options.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in options.changed_data))
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in options.changed_data
)
)
messages.success(request, "Préférences modifiées")
return redirect("/preferences/")
return form({'options': options}, 'preferences/edit_preferences.html', request)
return form(
{'options': options},
'preferences/edit_preferences.html',
request
)
else:
messages.error(request, "Objet inconnu")
return redirect("/preferences/")
@login_required
@permission_required('admin')
def add_services(request):
"""Ajout d'un service de la page d'accueil"""
services = ServiceForm(request.POST or None)
if services.is_valid():
with transaction.atomic(), reversion.create_revision():
......@@ -98,29 +116,45 @@ def add_services(request):
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement ns a été ajouté")
return redirect("/preferences/")
return form({'preferenceform': services}, 'preferences/preferences.html', request)
return form(
{'preferenceform': services},
'preferences/preferences.html',
request
)
@login_required
@permission_required('admin')
def edit_services(request, servicesid):
"""Edition des services affichés sur la page d'accueil"""
try:
services_instance = Service.objects.get(pk=servicesid)
except Service.DoesNotExist:
messages.error(request, u"Entrée inexistante" )
messages.error(request, u"Entrée inexistante")
return redirect("/preferences/")
services = ServiceForm(request.POST or None, instance=services_instance)
if services.is_valid():
with transaction.atomic(), reversion.create_revision():
services.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in services.changed_data))
reversion.set_comment(
"Champs modifié(s) : %s" % ', '.join(
field for field in services.changed_data
)
)
messages.success(request, "Service modifié")
return redirect("/preferences/")
return form({'preferenceform': services}, 'preferences/preferences.html', request)
return form(
{'preferenceform': services},
'preferences/preferences.html',
request
)
@login_required
@permission_required('admin')
def del_services(request):
"""Suppression d'un service de la page d'accueil"""
services = DelServiceForm(request.POST or None)
if services.is_valid():
services_dels = services.cleaned_data['services']
......@@ -131,20 +165,28 @@ def del_services(request):
reversion.set_user(request.user)
messages.success(request, "Le services a été supprimée")
except ProtectedError:
messages.error(request, "Erreur le service suivant %s ne peut être supprimé" % services_del)
messages.error(request, "Erreur le service\
suivant %s ne peut être supprimé" % services_del)
return redirect("/preferences/")
return form({'preferenceform': services}, 'preferences/preferences.html', request)
return form(
{'preferenceform': services},
'preferences/preferences.html',
request
)
@login_required
@permission_required('cableur')
def history(request, object, id):
if object == 'service':
def history(request, object_name, object_id):
"""Historique de creation et de modification d'un service affiché sur
la page d'accueil"""
if object_name == 'service':
try:
object_instance = Service.objects.get(pk=id)
object_instance = Service.objects.get(pk=object_id)
except Service.DoesNotExist:
messages.error(request, "Service inexistant")
return redirect("/preferences/")
options, created = GeneralOption.objects.get_or_create()
messages.error(request, "Service inexistant")
return redirect("/preferences/")
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
reversions = Version.objects.get_for_object(object_instance)
paginator = Paginator(reversions, pagination_number)
......@@ -157,4 +199,7 @@ def history(request, object, id):
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
reversions = paginator.page(paginator.num_pages)
return render(request, 're2o/history.html', {'reversions': reversions, 'object': object_instance})
return render(request, 're2o/history.html', {
'reversions': reversions,
'object': object_instance
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment