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., - + 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
Nombre de jours avant le rappelNombre de jours avant la fin d'adhésion Message custom pour ce rappel
- {% for line in topologieoptions %} - {% for text, field in line %} - - - {% endfor %} + + + + + + + + + +
{{ field }}{{ text }}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%}
+ + + + - {% endfor %}
Switchs configurés automatiquement{{ topologieoptions.provisioned_switchs|join:", " }}

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.,
{% csrf_token %} {% massive_bootstrap_form options 'utilisateur_asso' %} +{% massive_bootstrap_form options 'automatic_provision_switchs' %} {% bootstrap_button "Modifier" button_type="submit" icon="star" %}

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)