diff --git a/preferences/forms.py b/preferences/forms.py
index be4d1655..7b570dac 100644
--- a/preferences/forms.py
+++ b/preferences/forms.py
@@ -40,6 +40,7 @@ from .models import (
MailContact,
Reminder
)
+from topologie.models import Switch
class EditOptionalUserForm(ModelForm):
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
@@ -77,7 +78,14 @@ class EditOptionalMachineForm(ModelForm):
class EditOptionalTopologieForm(ModelForm):
- """Options de topologie, formulaire d'edition (vlan par default etc)"""
+ """Options de topologie, formulaire d'edition (vlan par default etc)
+ On rajoute un champ automatic provision switchs pour gérer facilement
+ l'ajout de switchs au provisionning automatique"""
+ automatic_provision_switchs = forms.ModelMultipleChoiceField(
+ Switch.objects.all(),
+ required=False
+ )
+
class Meta:
model = OptionalTopologie
fields = '__all__'
@@ -94,6 +102,14 @@ class EditOptionalTopologieForm(ModelForm):
self.fields['vlan_decision_nok'].label = "Vlan où placer les\
machines après rejet RADIUS"
+ self.initial['automatic_provision_switchs'] = Switch.objects.filter(automatic_provision=True)
+
+ def save(self, commit=True):
+ instance = super().save(commit)
+ Switch.objects.all().update(automatic_provision=False)
+ self.cleaned_data['automatic_provision_switchs'].update(automatic_provision=True)
+ return instance
+
class EditGeneralOptionForm(ModelForm):
"""Options générales (affichages de résultats de recherche, etc)"""
diff --git a/preferences/migrations/0040_auto_20180703_0743.py b/preferences/migrations/0040_auto_20180703_0743.py
new file mode 100644
index 00000000..45ed4d85
--- /dev/null
+++ b/preferences/migrations/0040_auto_20180703_0743.py
@@ -0,0 +1,193 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-07-03 05:43
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import preferences.aes_field
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('preferences', '0039_merge_20180701_1852'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='assooption',
+ name='adresse1',
+ field=models.CharField(default='1 Rue de exemple', help_text='Adresse', max_length=128),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='contact',
+ field=models.EmailField(default='contact@example.org', help_text='Mail de contact', max_length=254),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='description',
+ field=models.TextField(blank=True, help_text="Description de l'asso", null=True),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='name',
+ field=models.CharField(default='Association réseau école machin', help_text="Nom complet de l'asso", max_length=256),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='payment',
+ field=models.CharField(choices=[('NONE', 'NONE'), ('COMNPAY', 'COMNPAY')], default='NONE', help_text='Mode de paiement en ligne', max_length=255),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='payment_id',
+ field=models.CharField(blank=True, default='', help_text='Id de paiement en ligne', max_length=255),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='payment_pass',
+ field=preferences.aes_field.AESEncryptedField(blank=True, help_text='Clef de paiement en ligne', max_length=255, null=True),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='pseudo',
+ field=models.CharField(default='Asso', help_text="Pseudo de l'asso", max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='siret',
+ field=models.CharField(default='00000000000000', help_text='Numero SIRET', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='telephone',
+ field=models.CharField(default='0000000000', help_text='Téléphone de contact', max_length=15),
+ ),
+ migrations.AlterField(
+ model_name='assooption',
+ name='utilisateur_asso',
+ field=models.OneToOneField(blank=True, help_text="Utilisateur dans la db correspondant à l'asso", null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='GTU',
+ field=models.FileField(blank=True, default='', help_text="CGU et documents réglementaires à l'inscription", null=True, upload_to=''),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='GTU_sum_up',
+ field=models.TextField(blank=True, default='', help_text="Résumé des CGU à l'inscription"),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='email_from',
+ field=models.EmailField(default='www-data@example.com', help_text='From des mails envoyés par re2o', max_length=254),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='general_message',
+ field=models.TextField(blank=True, default='', help_text='Message général affiché sur le site (maintenance, etc)'),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='pagination_large_number',
+ field=models.IntegerField(default=8, help_text="Nombre d'item par page paginée, items larges"),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='pagination_number',
+ field=models.IntegerField(default=25, help_text="Nombre d'item par page paginée"),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='req_expire_hrs',
+ field=models.IntegerField(default=48, help_text="Delais d'expiration des token changement de mdp, en heure"),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='search_display_page',
+ field=models.IntegerField(default=15, help_text='Nombre de résultats affichés dans une recherche'),
+ ),
+ migrations.AlterField(
+ model_name='generaloption',
+ name='site_name',
+ field=models.CharField(default='Re2o', help_text='Nom du site web, par defaut re2o', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='optionalmachine',
+ name='ipv6_mode',
+ field=models.CharField(choices=[('SLAAC', 'Autoconfiguration par RA'), ('DHCPV6', 'Attribution des ip par dhcpv6'), ('DISABLED', 'Désactivé')], default='DISABLED', help_text='Mode ipv6', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='optionalmachine',
+ name='max_lambdauser_aliases',
+ field=models.IntegerField(default=10, help_text='Maximum de cname pour un user sans droits'),
+ ),
+ migrations.AlterField(
+ model_name='optionalmachine',
+ name='max_lambdauser_interfaces',
+ field=models.IntegerField(default=10, help_text="Maximum d'interface pour un user sans droits"),
+ ),
+ migrations.AlterField(
+ model_name='optionalmachine',
+ name='password_machine',
+ field=models.BooleanField(default=False, help_text='Un mot de passe par machine activé'),
+ ),
+ migrations.AlterField(
+ model_name='optionaltopologie',
+ name='radius_general_policy',
+ field=models.CharField(choices=[('MACHINE', 'Sur le vlan de la plage ip machine'), ('DEFINED', 'Prédéfini dans "Vlan où placer les machines après acceptation RADIUS"')], default='DEFINED', help_text='Politique par defaut de placement de vlan avec radius', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='optionaltopologie',
+ name='vlan_decision_nok',
+ field=models.OneToOneField(blank=True, help_text='Placement par defaut sur ce vlan en cas de rejet', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='decision_nok', to='machines.Vlan'),
+ ),
+ migrations.AlterField(
+ model_name='optionaltopologie',
+ name='vlan_decision_ok',
+ field=models.OneToOneField(blank=True, help_text="Placement sur ce vlan par default en cas d'accès OK", null=True, on_delete=django.db.models.deletion.PROTECT, related_name='decision_ok', to='machines.Vlan'),
+ ),
+ migrations.AlterField(
+ model_name='optionaluser',
+ name='gpg_fingerprint',
+ field=models.BooleanField(default=True, help_text='Gpg fingerprint activée'),
+ ),
+ migrations.AlterField(
+ model_name='optionaluser',
+ name='is_tel_mandatory',
+ field=models.BooleanField(default=True, help_text='Obligation de renseigner le téléphone'),
+ ),
+ migrations.AlterField(
+ model_name='optionaluser',
+ name='max_solde',
+ field=models.DecimalField(decimal_places=2, default=50, help_text='Valeur maximum du solde', max_digits=5),
+ ),
+ migrations.AlterField(
+ model_name='optionaluser',
+ name='min_online_payment',
+ field=models.DecimalField(decimal_places=2, default=10, help_text='Montant minimum pour le rechargement online', max_digits=5),
+ ),
+ migrations.AlterField(
+ model_name='optionaluser',
+ name='shell_default',
+ field=models.OneToOneField(blank=True, help_text='Shell par default', null=True, on_delete=django.db.models.deletion.PROTECT, to='users.ListShell'),
+ ),
+ migrations.AlterField(
+ model_name='optionaluser',
+ name='solde_negatif',
+ field=models.DecimalField(decimal_places=2, default=0, help_text='Maximum de négatif autorisé', max_digits=5),
+ ),
+ migrations.AlterField(
+ model_name='optionaluser',
+ name='user_solde',
+ field=models.BooleanField(default=False, help_text='Solde pour les users'),
+ ),
+ migrations.AlterField(
+ model_name='reminder',
+ name='message',
+ field=models.CharField(blank=True, default='', help_text='Message affiché spécifiquement pour ce rappel', max_length=255, null=True),
+ ),
+ ]
diff --git a/preferences/migrations/0041_generaloption_site_url.py b/preferences/migrations/0041_generaloption_site_url.py
new file mode 100644
index 00000000..584dea91
--- /dev/null
+++ b/preferences/migrations/0041_generaloption_site_url.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-07-03 19:57
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('preferences', '0040_auto_20180703_0743'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='generaloption',
+ name='site_url',
+ field=models.CharField(default='re2o.org', help_text='url par défaut du site. par défaut: re2o.org', max_length=32),
+ ),
+ ]
diff --git a/preferences/migrations/0042_auto_20180703_2222.py b/preferences/migrations/0042_auto_20180703_2222.py
new file mode 100644
index 00000000..21ad297c
--- /dev/null
+++ b/preferences/migrations/0042_auto_20180703_2222.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-07-03 20:22
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('preferences', '0041_generaloption_site_url'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='generaloption',
+ name='site_url',
+ field=models.CharField(default='re2o.example.org', help_text='url par défaut du site. par défaut: re2o.example.org', max_length=32),
+ ),
+ ]
diff --git a/preferences/migrations/0043_auto_20180709_1947.py b/preferences/migrations/0043_auto_20180709_1947.py
new file mode 100644
index 00000000..121d8bad
--- /dev/null
+++ b/preferences/migrations/0043_auto_20180709_1947.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-07-09 17:47
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0092_auto_20180708_2018'),
+ ('preferences', '0042_auto_20180703_2222'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='optionaltopologie',
+ name='switchs_ip_type',
+ field=models.OneToOneField(blank=True, help_text="Plage d'ip de management des switchs", null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpType'),
+ ),
+ migrations.AddField(
+ model_name='optionaltopologie',
+ name='switchs_rest_management',
+ field=models.BooleanField(default=False, help_text='Rest management, activé si provision auto'),
+ ),
+ migrations.AddField(
+ model_name='optionaltopologie',
+ name='switchs_web_management',
+ field=models.BooleanField(default=False, help_text='Web management, activé si provision automatique'),
+ ),
+ ]
diff --git a/preferences/models.py b/preferences/models.py
index 01abbc0d..13d0709b 100644
--- a/preferences/models.py
+++ b/preferences/models.py
@@ -35,6 +35,7 @@ from django.core.cache import cache
from django.forms import ValidationError
import cotisations.models
import machines.models
+
from re2o.mixins import AclMixin
@@ -248,6 +249,26 @@ class OptionalTopologie(AclMixin, PreferencesModel):
null=True,
help_text="Placement par defaut sur ce vlan en cas de rejet"
)
+ switchs_web_management = models.BooleanField(
+ default=False,
+ help_text="Web management, activé si provision automatique"
+ )
+ switchs_rest_management = models.BooleanField(
+ default=False,
+ help_text="Rest management, activé si provision auto"
+ )
+ switchs_ip_type = models.OneToOneField(
+ 'machines.IpType',
+ on_delete=models.PROTECT,
+ blank=True,
+ null=True,
+ help_text="Plage d'ip de management des switchs"
+ )
+
+ @cached_property
+ def provisioned_switchs(self):
+ from topologie.models import Switch
+ return Switch.objects.filter(automatic_provision=True)
class Meta:
permissions = (
@@ -326,6 +347,11 @@ class GeneralOption(AclMixin, PreferencesModel):
default="Re2o",
help_text="Nom du site web, par defaut re2o"
)
+ site_url = models.CharField(
+ max_length=32,
+ default="re2o.example.org",
+ help_text="url par défaut du site. par défaut: re2o.example.org"
+ )
email_from = models.EmailField(
default="www-data@example.com",
help_text="From des mails envoyés par re2o"
diff --git a/preferences/templates/preferences/aff_reminder.html b/preferences/templates/preferences/aff_reminder.html
index 4bcaacce..55d5a428 100644
--- a/preferences/templates/preferences/aff_reminder.html
+++ b/preferences/templates/preferences/aff_reminder.html
@@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- Nombre de jours avant le rappel |
+ Nombre de jours avant la fin d'adhésion |
Message custom pour ce rappel |
|
|
diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html
index 82a2d670..633072ee 100644
--- a/preferences/templates/preferences/display_preferences.html
+++ b/preferences/templates/preferences/display_preferences.html
@@ -111,15 +111,41 @@ with this program; if not, write to the Free Software Foundation, Inc.,
+ Préférences authentification radius
- {% for line in topologieoptions %}
- {% for text, field in line %}
- {{ field }} |
- {{ text }} |
- {% endfor %}
+ Politique par defaut de placement de vlan avec radius |
+ {{ topologieoptions.radius_general_policy }} |
+ Placement sur ce vlan par default en cas d'accès OK |
+ {{ topologieoptions.vlan_decision_ok }} |
+
+
+ Placement sur ce vlan par default en cas de rejet |
+ {{ topologieoptions.vlan_decision_nok }} |
+
+
+
+ Configuration des switches
+
+
+ Web management, activé si provision automatique |
+ {{ topologieoptions.switchs_web_management }} |
+ Rest management, activé si provision auto |
+ {{ topologieoptions.switchs_rest_management }} |
+
+
+ Plage d'ip de management des switchs |
+ {{ topologieoptions.switchs_ip_type }} |
+
+
+
+
+ {% if topologieoptions.provisioned_switchs %}Provision de la config des switchs{% else %}Provision de la config des switchs{% endif%}
+
+
+ Switchs configurés automatiquement |
+ {{ topologieoptions.provisioned_switchs|join:", " }} |
- {% endfor %}
Préférences generales
diff --git a/preferences/templates/preferences/edit_preferences.html b/preferences/templates/preferences/edit_preferences.html
index 055ac7e8..7c01ef4d 100644
--- a/preferences/templates/preferences/edit_preferences.html
+++ b/preferences/templates/preferences/edit_preferences.html
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
diff --git a/preferences/views.py b/preferences/views.py
index 419333f9..89df12c1 100644
--- a/preferences/views.py
+++ b/preferences/views.py
@@ -87,9 +87,9 @@ def display_options(request):
mailcontact_list = MailContact.objects.all()
reminder_list = Reminder.objects.all()
return form({
- 'useroptions': format_options(useroptions),
+ 'useroptions': useroptions,
'machineoptions': format_options(machineoptions),
- 'topologieoptions': format_options(topologieoptions),
+ 'topologieoptions': topologieoptions,
'generaloptions': format_options(generaloptions),
'assooptions': format_options(assooptions),
'homeoptions': format_options(homeoptions),
diff --git a/topologie/migrations/0069_switch_automatic_provision.py b/topologie/migrations/0069_switch_automatic_provision.py
new file mode 100644
index 00000000..6fb160a6
--- /dev/null
+++ b/topologie/migrations/0069_switch_automatic_provision.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-07-09 17:47
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('topologie', '0068_modelswitch_firmware'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='switch',
+ name='automatic_provision',
+ field=models.BooleanField(default=False, help_text='Provision automatique de ce switch'),
+ ),
+ ]
diff --git a/topologie/models.py b/topologie/models.py
index b11374c6..55f9aee6 100644
--- a/topologie/models.py
+++ b/topologie/models.py
@@ -49,6 +49,7 @@ from django.db import transaction
from django.utils.translation import ugettext_lazy as _
from reversion import revisions as reversion
+from preferences.models import OptionalTopologie
from machines.models import Machine, regen
from re2o.mixins import AclMixin, RevMixin
@@ -216,6 +217,10 @@ class Switch(AclMixin, Machine):
on_delete=models.SET_NULL,
help_text="Baie de brassage du switch"
)
+ automatic_provision = models.BooleanField(
+ default=False,
+ help_text='Provision automatique de ce switch',
+ )
class Meta:
unique_together = ('stack', 'stack_member_id')
@@ -271,6 +276,14 @@ class Switch(AclMixin, Machine):
""" Returns the 'main' interface of the switch """
return self.interface_set.first()
+ @cached_property
+ def rest_enabled(self):
+ return OptionalTopologie.get_cached_value('switchs_rest_management') or self.automatic_provision
+
+ @cached_property
+ def web_management_enabled(self):
+ return OptionalTopologie.get_cached_value('switchs_web_management') or self.automatic_provision
+
@cached_property
def ipv4(self):
return str(self.main_interface().ipv4)