mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-08-20 06:03:40 +00:00
Gestion des extensions avec un modèle
This commit is contained in:
parent
7c37fce648
commit
351dd6bce0
13 changed files with 186 additions and 27 deletions
|
@ -1,12 +1,15 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Machine, MachineType, IpList, Interface
|
||||
from .models import Machine, MachineType, IpList, Interface, Extension
|
||||
|
||||
class MachineAdmin(admin.ModelAdmin):
|
||||
list_display = ('user','name','type','active')
|
||||
|
||||
class MachineTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ('type',)
|
||||
list_display = ('type','extension')
|
||||
|
||||
class ExtensionAdmin(admin.ModelAdmin):
|
||||
list_display = ('name',)
|
||||
|
||||
class IpListAdmin(admin.ModelAdmin):
|
||||
list_display = ('ipv4',)
|
||||
|
@ -16,5 +19,6 @@ class InterfaceAdmin(admin.ModelAdmin):
|
|||
|
||||
admin.site.register(Machine, MachineAdmin)
|
||||
admin.site.register(MachineType, MachineTypeAdmin)
|
||||
admin.site.register(Extension, ExtensionAdmin)
|
||||
admin.site.register(IpList, IpListAdmin)
|
||||
admin.site.register(Interface, InterfaceAdmin)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.forms import ModelForm, Form, ValidationError
|
||||
from django import forms
|
||||
from .models import Machine, Interface, MachineType
|
||||
from .models import Machine, Interface, MachineType, Extension
|
||||
|
||||
class EditMachineForm(ModelForm):
|
||||
class Meta:
|
||||
|
@ -42,7 +42,7 @@ class NewInterfaceForm(EditInterfaceForm):
|
|||
class MachineTypeForm(ModelForm):
|
||||
class Meta:
|
||||
model = MachineType
|
||||
fields = ['type']
|
||||
fields = ['type','extension']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MachineTypeForm, self).__init__(*args, **kwargs)
|
||||
|
@ -52,5 +52,21 @@ class DelMachineTypeForm(ModelForm):
|
|||
machinetypes = forms.ModelMultipleChoiceField(queryset=MachineType.objects.all(), label="Types de machines actuelles", widget=forms.CheckboxSelectMultiple)
|
||||
|
||||
class Meta:
|
||||
exclude = ['type']
|
||||
exclude = ['type','extension']
|
||||
model = MachineType
|
||||
|
||||
class ExtensionForm(ModelForm):
|
||||
class Meta:
|
||||
model = Extension
|
||||
fields = ['name']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ExtensionForm, self).__init__(*args, **kwargs)
|
||||
self.fields['name'].label = 'Exstension à ajouter'
|
||||
|
||||
class DelExtensionForm(ModelForm):
|
||||
extensions = forms.ModelMultipleChoiceField(queryset=Extension.objects.all(), label="Extensions actuelles", widget=forms.CheckboxSelectMultiple)
|
||||
|
||||
class Meta:
|
||||
exclude = ['name']
|
||||
model = Extension
|
||||
|
|
33
machines/migrations/0016_auto_20160708_1633.py
Normal file
33
machines/migrations/0016_auto_20160708_1633.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import machines.models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('machines', '0015_auto_20160707_0105'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Extension',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
],
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interface',
|
||||
name='dns',
|
||||
field=models.CharField(unique=True, max_length=255, validators=[machines.models.full_domain_validator], help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter d'autres points"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='machinetype',
|
||||
name='extension',
|
||||
field=models.ForeignKey(null=True, blank=True, on_delete=django.db.models.deletion.PROTECT, to='machines.Extension'),
|
||||
),
|
||||
]
|
21
machines/migrations/0017_auto_20160708_1645.py
Normal file
21
machines/migrations/0017_auto_20160708_1645.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('machines', '0016_auto_20160708_1633'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='machinetype',
|
||||
name='extension',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, default=1, to='machines.Extension'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -2,31 +2,30 @@ from django.db import models
|
|||
from django.forms import ValidationError
|
||||
from macaddress.fields import MACAddressField
|
||||
|
||||
from django.conf import settings
|
||||
import re
|
||||
|
||||
def full_domain_validator(hostname):
|
||||
""" Validation du nom de domaine, extensions dans settings, prefixe pas plus long que 63 caractères """
|
||||
def full_domain_validator(interface):
|
||||
""" Validation du nom de domaine, extensions dans type de machine, prefixe pas plus long que 63 caractères """
|
||||
HOSTNAME_LABEL_PATTERN = re.compile("(?!-)[A-Z\d-]+(?<!-)$", re.IGNORECASE)
|
||||
if not any(ext in hostname for ext in settings.ALLOWED_EXTENSIONS):
|
||||
dns = interface.dns.lower()
|
||||
allowed_extension = interface.machine.type.extension.name
|
||||
if not dns.endswith(allowed_extension):
|
||||
raise ValidationError(
|
||||
", le nom de domaine '%(label)s' doit comporter une extension valide",
|
||||
params={'label': hostname},
|
||||
"Le nom de domaine '%(label)s' doit comporter une extension valide en '%(extension)s'",
|
||||
params={'label': dns, 'extension': allowed_extension},
|
||||
)
|
||||
for extension in settings.ALLOWED_EXTENSIONS:
|
||||
if hostname.endswith(extension):
|
||||
hostname=re.sub('%s$' % extension, '', hostname)
|
||||
break
|
||||
if len(hostname) > 63:
|
||||
dns_short=re.sub('%s$' % allowed_extension, '', dns)
|
||||
if len(dns_short) > 63:
|
||||
raise ValidationError(
|
||||
", le nom de domaine '%(label)s' est trop long (maximum de 63 caractères).",
|
||||
params={'label': hostname},
|
||||
"Le nom de domaine '%(label)s' est trop long (maximum de 63 caractères).",
|
||||
params={'label': dns},
|
||||
)
|
||||
if not HOSTNAME_LABEL_PATTERN.match(hostname):
|
||||
if not HOSTNAME_LABEL_PATTERN.match(dns_short):
|
||||
raise ValidationError(
|
||||
", ce nom de domaine '%(label)s' contient des carractères interdits.",
|
||||
params={'label': hostname},
|
||||
"Ce nom de domaine '%(label)s' contient des carractères interdits.",
|
||||
params={'label': dns},
|
||||
)
|
||||
return dns
|
||||
|
||||
class Machine(models.Model):
|
||||
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
|
||||
|
@ -39,10 +38,16 @@ class Machine(models.Model):
|
|||
|
||||
class MachineType(models.Model):
|
||||
type = models.CharField(max_length=255)
|
||||
extension = models.ForeignKey('Extension', on_delete=models.PROTECT)
|
||||
|
||||
def __str__(self):
|
||||
return self.type
|
||||
|
||||
class Extension(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Interface(models.Model):
|
||||
ipv4 = models.OneToOneField('IpList', on_delete=models.PROTECT, blank=True, null=True)
|
||||
|
@ -50,13 +55,13 @@ class Interface(models.Model):
|
|||
mac_address = MACAddressField(integer=False, unique=True)
|
||||
machine = models.ForeignKey('Machine', on_delete=models.PROTECT)
|
||||
details = models.CharField(max_length=255, blank=True)
|
||||
dns = models.CharField(help_text="Obligatoire et unique, doit se terminer en %s et ne pas comporter d'autres points" % ", ".join(settings.ALLOWED_EXTENSIONS), max_length=255, unique=True, validators=[full_domain_validator])
|
||||
dns = models.CharField(help_text="Obligatoire et unique, doit se terminer en %s et ne pas comporter d'autres points" % ", ".join(Extension.objects.values_list('name', flat=True)), max_length=255, unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.dns
|
||||
|
||||
def clean(self):
|
||||
self.dns=self.dns.lower()
|
||||
self.dns=full_domain_validator(self)
|
||||
|
||||
class IpList(models.Model):
|
||||
ipv4 = models.GenericIPAddressField(protocol='IPv4', unique=True)
|
||||
|
|
15
machines/templates/machines/aff_extension.html
Normal file
15
machines/templates/machines/aff_extension.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Extension</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for extension in extension_list %}
|
||||
<tr>
|
||||
<td>{{ extension.name }}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:edit-extension' extension.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
@ -2,12 +2,14 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Type de machine</th>
|
||||
<th>Extension</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for type in machinetype_list %}
|
||||
<tr>
|
||||
<td>{{ type.type }}</td>
|
||||
<td>{{ type.extension }}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:edit-machinetype' type.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
15
machines/templates/machines/index_extension.html
Normal file
15
machines/templates/machines/index_extension.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "machines/sidebar.html" %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Machines{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Liste des extensions</h2>
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:add-extension' %}"><i class="glyphicon glyphicon-plus"></i> Ajouter une extension</a>
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:del-extension' %}"><i class="glyphicon glyphicon-trash"></i> Supprimer une ou plusieurs extensions</a>
|
||||
{% include "machines/aff_extension.html" with extension_list=extension_list %}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{% endblock %}
|
||||
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
{% block sidebar %}
|
||||
<p><a href="{% url "machines:index-machinetype" %}">Liste des types de machine</a></p>
|
||||
<p><a href="{% url "machines:index-extension" %}">Liste des types des extensions</a></p>
|
||||
{% endblock %}
|
||||
|
|
|
@ -10,5 +10,9 @@ urlpatterns = [
|
|||
url(r'^edit_machinetype/(?P<machinetypeid>[0-9]+)$', views.edit_machinetype, name='edit-machinetype'),
|
||||
url(r'^del_machinetype/$', views.del_machinetype, name='del-machinetype'),
|
||||
url(r'^index_machinetype/$', views.index_machinetype, name='index-machinetype'),
|
||||
url(r'^add_extension/$', views.add_extension, name='add-extension'),
|
||||
url(r'^edit_extension/(?P<extensionid>[0-9]+)$', views.edit_extension, name='edit-extension'),
|
||||
url(r'^del_extension/$', views.del_extension, name='del-extension'),
|
||||
url(r'^index_extension/$', views.index_extension, name='index-extension'),
|
||||
url(r'^$', views.index, name='index'),
|
||||
]
|
||||
|
|
|
@ -9,8 +9,8 @@ from django.contrib import messages
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import ProtectedError
|
||||
|
||||
from .forms import NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm, NewInterfaceForm, MachineTypeForm, DelMachineTypeForm
|
||||
from .models import Machine, Interface, IpList, MachineType
|
||||
from .forms import NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm, NewInterfaceForm, MachineTypeForm, DelMachineTypeForm, ExtensionForm, DelExtensionForm
|
||||
from .models import Machine, Interface, IpList, MachineType, Extension
|
||||
from users.models import User
|
||||
|
||||
def unassign_ips(user):
|
||||
|
@ -147,6 +147,43 @@ def del_machinetype(request):
|
|||
return redirect("/machines/index_machinetype")
|
||||
return form({'machineform': machinetype, 'interfaceform': None}, 'machines/machine.html', request)
|
||||
|
||||
@login_required
|
||||
def add_extension(request):
|
||||
extension = ExtensionForm(request.POST or None)
|
||||
if extension.is_valid():
|
||||
extension.save()
|
||||
messages.success(request, "Cette extension a été ajoutée")
|
||||
return redirect("/machines/index_extension")
|
||||
return form({'machineform': extension, 'interfaceform': None}, 'machines/machine.html', request)
|
||||
|
||||
@login_required
|
||||
def edit_extension(request, extensionid):
|
||||
try:
|
||||
extension_instance = Extension.objects.get(pk=extensionid)
|
||||
except Extension.DoesNotExist:
|
||||
messages.error(request, u"Entrée inexistante" )
|
||||
return redirect("/machines/index_extension/")
|
||||
extension = ExtensionForm(request.POST or None, instance=extension_instance)
|
||||
if extension.is_valid():
|
||||
extension.save()
|
||||
messages.success(request, "Extension modifiée")
|
||||
return redirect("/machines/index_extension/")
|
||||
return form({'machineform': extension}, 'machines/machine.html', request)
|
||||
|
||||
@login_required
|
||||
def del_extension(request):
|
||||
extension = DelExtensionForm(request.POST or None)
|
||||
if extension.is_valid():
|
||||
extension_dels = extension.cleaned_data['extensions']
|
||||
for extension_del in extension_dels:
|
||||
try:
|
||||
extension_del.delete()
|
||||
messages.success(request, "L'extension a été supprimée")
|
||||
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)
|
||||
return redirect("/machines/index_extension")
|
||||
return form({'machineform': extension, 'interfaceform': None}, 'machines/machine.html', request)
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
interfaces_list = Interface.objects.order_by('pk')
|
||||
|
@ -156,3 +193,8 @@ def index(request):
|
|||
def index_machinetype(request):
|
||||
machinetype_list = MachineType.objects.order_by('type')
|
||||
return render(request, 'machines/index_machinetype.html', {'machinetype_list':machinetype_list})
|
||||
|
||||
@login_required
|
||||
def index_extension(request):
|
||||
extension_list = Extension.objects.order_by('name')
|
||||
return render(request, 'machines/index_extension.html', {'extension_list':extension_list})
|
||||
|
|
|
@ -12,7 +12,7 @@ https://docs.djangoproject.com/en/1.8/ref/settings/
|
|||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
import os
|
||||
from .settings_local import SECRET_KEY, DATABASES, DEBUG, ALLOWED_HOSTS, ALLOWED_EXTENSIONS
|
||||
from .settings_local import SECRET_KEY, DATABASES, DEBUG, ALLOWED_HOSTS
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
@ -117,3 +117,5 @@ STATICFILES_DIRS = (
|
|||
)
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
LOGIN_URL = '/admin/'
|
||||
|
|
|
@ -17,4 +17,3 @@ DATABASES = {
|
|||
}
|
||||
}
|
||||
|
||||
ALLOWED_EXTENSIONS = ['.example']
|
||||
|
|
Loading…
Reference in a new issue