mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-25 22:22:26 +00:00
Merge branch 'fix_stack' into 'master'
Fix stack Closes #104 and #108 See merge request federez/re2o!140
This commit is contained in:
commit
5453b845e2
14 changed files with 2249 additions and 71 deletions
|
@ -27,9 +27,16 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.forms import ModelForm, Form
|
||||
from django import forms
|
||||
from .models import OptionalUser, OptionalMachine, OptionalTopologie
|
||||
from .models import GeneralOption, AssoOption, MailMessageOption, Service
|
||||
|
||||
from .models import (
|
||||
OptionalUser,
|
||||
OptionalMachine,
|
||||
OptionalTopologie,
|
||||
GeneralOption,
|
||||
AssoOption,
|
||||
MailMessageOption,
|
||||
AccueilOption,
|
||||
Service
|
||||
)
|
||||
|
||||
class EditOptionalUserForm(ModelForm):
|
||||
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
|
||||
|
@ -185,6 +192,21 @@ class EditMailMessageOptionForm(ModelForm):
|
|||
mail de bienvenue en anglais'
|
||||
|
||||
|
||||
class EditAccueilOptionForm(ModelForm):
|
||||
"""Formulaire d'édition des options de la page d'accueil"""
|
||||
class Meta:
|
||||
model = AccueilOption
|
||||
fields = '__all__'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
super(EditAccueilOptionForm, self).__init__(
|
||||
*args,
|
||||
prefix=prefix,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
class ServiceForm(ModelForm):
|
||||
"""Edition, ajout de services sur la page d'accueil"""
|
||||
class Meta:
|
||||
|
|
29
preferences/migrations/0033_accueiloption.py
Normal file
29
preferences/migrations/0033_accueiloption.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2018-04-16 02:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import re2o.mixins
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('preferences', '0032_optionaluser_shell_default'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AccueilOption',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('facebook_url', models.URLField(blank=True, help_text='Url du compte facebook', null=True)),
|
||||
('twitter_url', models.URLField(blank=True, help_text='Url du compte twitter', null=True)),
|
||||
('twitter_account_name', models.CharField(blank=True, help_text='Nom du compte à afficher', max_length=32, null=True)),
|
||||
],
|
||||
options={
|
||||
'permissions': (('view_accueiloption', "Peut voir les options de l'accueil"),),
|
||||
},
|
||||
bases=(re2o.mixins.AclMixin, models.Model),
|
||||
),
|
||||
]
|
|
@ -331,6 +331,40 @@ def assooption_post_save(**kwargs):
|
|||
asso_pref.set_in_cache()
|
||||
|
||||
|
||||
class AccueilOption(AclMixin, PreferencesModel):
|
||||
"""Reglages de la page d'accueil"""
|
||||
PRETTY_NAME = "Options de la page d'accueil"
|
||||
|
||||
facebook_url = models.URLField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Url du compte facebook"
|
||||
)
|
||||
twitter_url = models.URLField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Url du compte twitter"
|
||||
)
|
||||
twitter_account_name = models.CharField(
|
||||
max_length=32,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Nom du compte à afficher"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("view_accueiloption", "Peut voir les options de l'accueil"),
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_save, sender=AccueilOption)
|
||||
def accueiloption_post_save(**kwargs):
|
||||
"""Ecriture dans le cache"""
|
||||
accueil_pref = kwargs['instance']
|
||||
accueil_pref.set_in_cache()
|
||||
|
||||
|
||||
class MailMessageOption(AclMixin, models.Model):
|
||||
"""Reglages, mail de bienvenue et autre"""
|
||||
PRETTY_NAME = "Options de corps de mail"
|
||||
|
|
|
@ -211,12 +211,31 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<td>{{ mailmessageoptions.welcome_mail_en | safe }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>Liste des services page d'accueil</h2>
|
||||
<h2>Liste des services et préférences page d'accueil</h2>
|
||||
{% can_create preferences.Service%}
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-service' %}"><i class="fa fa-plus"></i> Ajouter un service</a>
|
||||
{% acl_end %}
|
||||
<a class="btn btn-danger btn-sm" role="button" href="{% url 'preferences:del-services' %}"><i class="fa fa-trash"></i> Supprimer un ou plusieurs service</a>
|
||||
{% include "preferences/aff_service.html" with service_list=service_list %}
|
||||
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'AccueilOption' %}">
|
||||
<i class="fa fa-edit"></i>
|
||||
Editer
|
||||
</a>
|
||||
<p>
|
||||
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Url du compte twitter</th>
|
||||
<td>{{ accueiloptions.twitter_url }}</td>
|
||||
<th>Nom utilisé pour afficher le compte</th>
|
||||
<td>{{ accueiloptions.twitter_account_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Url du compte facebook</th>
|
||||
<td>{{ accueiloptions.facebook_url }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
|
|
@ -57,6 +57,11 @@ urlpatterns = [
|
|||
views.edit_options,
|
||||
name='edit-options'
|
||||
),
|
||||
url(
|
||||
r'^edit_options/(?P<section>AccueilOption)$',
|
||||
views.edit_options,
|
||||
name='edit-options'
|
||||
),
|
||||
url(
|
||||
r'^edit_options/(?P<section>MailMessageOption)$',
|
||||
views.edit_options,
|
||||
|
|
|
@ -43,8 +43,16 @@ from re2o.views import form
|
|||
from re2o.acl import can_create, can_edit, can_delete_set, can_view_all
|
||||
|
||||
from .forms import ServiceForm, DelServiceForm
|
||||
from .models import Service, OptionalUser, OptionalMachine, AssoOption
|
||||
from .models import MailMessageOption, GeneralOption, OptionalTopologie
|
||||
from .models import (
|
||||
Service,
|
||||
OptionalUser,
|
||||
OptionalMachine,
|
||||
AssoOption,
|
||||
MailMessageOption,
|
||||
GeneralOption,
|
||||
OptionalTopologie,
|
||||
AccueilOption
|
||||
)
|
||||
from . import models
|
||||
from . import forms
|
||||
|
||||
|
@ -56,6 +64,7 @@ from . import forms
|
|||
@can_view_all(GeneralOption)
|
||||
@can_view_all(AssoOption)
|
||||
@can_view_all(MailMessageOption)
|
||||
@can_view_all(AccueilOption)
|
||||
def display_options(request):
|
||||
"""Vue pour affichage des options (en vrac) classé selon les models
|
||||
correspondants dans un tableau"""
|
||||
|
@ -64,6 +73,7 @@ def display_options(request):
|
|||
topologieoptions, _created = OptionalTopologie.objects.get_or_create()
|
||||
generaloptions, _created = GeneralOption.objects.get_or_create()
|
||||
assooptions, _created = AssoOption.objects.get_or_create()
|
||||
accueiloptions, _created = AccueilOption.objects.get_or_create()
|
||||
mailmessageoptions, _created = MailMessageOption.objects.get_or_create()
|
||||
service_list = Service.objects.all()
|
||||
return form({
|
||||
|
@ -72,6 +82,7 @@ def display_options(request):
|
|||
'topologieoptions': topologieoptions,
|
||||
'generaloptions': generaloptions,
|
||||
'assooptions': assooptions,
|
||||
'accueiloptions': accueiloptions,
|
||||
'mailmessageoptions': mailmessageoptions,
|
||||
'service_list': service_list
|
||||
}, 'preferences/display_preferences.html', request)
|
||||
|
|
|
@ -25,4 +25,30 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
|
||||
{% block sidebar %}
|
||||
|
||||
{% if facebook_url %}
|
||||
<div class="fb-page" data-href="{{ facebook_url }}" data-tabs="timeline" data-small-header="false" data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="false"><blockquote cite="{{ facebook_url }}" class="fb-xfbml-parse-ignore"><a href="{{ facebook_url }}">{{ asso_name }}</a></blockquote></div>
|
||||
|
||||
<div id="fb-root"></div>
|
||||
<script>(function(d, s, id) {
|
||||
var js, fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) return;
|
||||
js = d.createElement(s); js.id = id;
|
||||
js.src = 'https://connect.facebook.net/fr_FR/sdk.js#xfbml=1&version=v2.12';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
}(document, 'script', 'facebook-jssdk'));</script>
|
||||
|
||||
<hr>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if twitter_url %}
|
||||
<a class="twitter-timeline" data-lang="fr" data-height="500" href="{{ twitter_url }}?ref_src=twsrc%5Etfw">Tweets de @{{ twitter_account_name }}</a>
|
||||
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
<a href="{{ twitter_url }}?ref_src=twsrc%5Etfw" class="twitter-follow-button" data-show-count="false"> Suivre @{{ twitter_account_name }}</a>
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -41,7 +41,12 @@ from django.utils.translation import ugettext as _
|
|||
from django.views.decorators.cache import cache_page
|
||||
|
||||
import preferences
|
||||
from preferences.models import Service, GeneralOption, AssoOption
|
||||
from preferences.models import (
|
||||
Service,
|
||||
GeneralOption,
|
||||
AssoOption,
|
||||
AccueilOption
|
||||
)
|
||||
import users
|
||||
import cotisations
|
||||
import topologie
|
||||
|
@ -63,7 +68,17 @@ def index(request):
|
|||
services = [[], [], []]
|
||||
for indice, serv in enumerate(Service.objects.all()):
|
||||
services[indice % 3].append(serv)
|
||||
return form({'services_urls': services}, 're2o/index.html', request)
|
||||
twitter_url = AccueilOption.get_cached_value('twitter_url')
|
||||
facebook_url = AccueilOption.get_cached_value('facebook_url')
|
||||
twitter_account_name = AccueilOption.get_cached_value('twitter_account_name')
|
||||
asso_name = AssoOption.get_cached_value('pseudo')
|
||||
return form({
|
||||
'services_urls': services,
|
||||
'twitter_url': twitter_url,
|
||||
'twitter_account_name' : twitter_account_name,
|
||||
'facebook_url': facebook_url,
|
||||
'asso_name': asso_name
|
||||
}, 're2o/index.html', request)
|
||||
|
||||
|
||||
#: Binding the corresponding char sequence of history url to re2o models.
|
||||
|
|
1929
static/js/jquery.ez-plus.js
Normal file
1929
static/js/jquery.ez-plus.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -31,58 +31,31 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<th>{% include "buttons/sort.html" with prefix='stack' col='id' text='ID' %}</th>
|
||||
<th>Détails</th>
|
||||
<th>Membres</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for stack in stack_list %}
|
||||
{% for switch in stack.switch_set.all %}
|
||||
<tbody>
|
||||
<tr class="active">
|
||||
{% if forloop.first %}
|
||||
<td rowspan="{{ stack.switch_set.all|length }}">{{stack.name}}</td>
|
||||
<td rowspan="{{ stack.switch_set.all|length }}">{{stack.stack_id}}</td>
|
||||
<td rowspan="{{ stack.switch_set.all|length }}" >{{stack.details}}</td>
|
||||
{% endif %}
|
||||
<td><a href="{% url 'topologie:index-port' switch.pk %}">{{switch}}</a></td>
|
||||
{% if forloop.first %}
|
||||
<td rowspan="{{ stack.switch_set.all|length }}">
|
||||
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'topologie:history' 'stack' stack.pk %}">
|
||||
<i class="fa fa-history"></i>
|
||||
</a>
|
||||
{% can_edit stack %}
|
||||
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'topologie:edit-stack' stack.id %}">
|
||||
<i class="fa fa-edit"></i>
|
||||
</a>
|
||||
{% acl_end %}
|
||||
{% can_delete stack %}
|
||||
<a class="btn btn-danger btn-sm" role="button" title="Supprimer" href="{% url 'topologie:del-stack' stack.pk %}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
{% acl_end %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr class="active">
|
||||
<td>{{stack.name}}</td>
|
||||
<td>{{stack.stack_id}}</td>
|
||||
<td>{{stack.details}}</td>
|
||||
<td>Aucun</td>
|
||||
<td>
|
||||
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'topologie:history' 'stack' stack.pk %}">
|
||||
<i class="fa fa-history"></i>
|
||||
</a>
|
||||
{% can_edit stack %}
|
||||
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'topologie:edit-stack' stack.id %}">
|
||||
<i class="fa fa-edit"></i>
|
||||
</a>
|
||||
{% acl_end %}
|
||||
{% can_delete stack %}
|
||||
<a class="btn btn-danger btn-sm" role="button" title="Supprimer" href="{% url 'topologie:del-stack' stack.pk %}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
{% acl_end %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endfor %}
|
||||
</thead>
|
||||
{% for stack in stack_list %}
|
||||
<tr>
|
||||
<td>{{ stack.name }}</td>
|
||||
<td>{{stack.stack_id}}</td>
|
||||
<td>{{stack.details}}</td>
|
||||
<td>{% for switch in stack.switch_set.all %}<a href="{% url 'topologie:index-port' switch.pk %}">{{switch }} </a>{% endfor %}</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'topologie:history' 'stack' stack.pk %}">
|
||||
<i class="fa fa-history"></i>
|
||||
</a>
|
||||
{% can_edit stack %}
|
||||
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'topologie:edit-stack' stack.id %}">
|
||||
<i class="fa fa-edit"></i>
|
||||
</a>
|
||||
{% acl_end %}
|
||||
{% can_delete stack %}
|
||||
<a class="btn btn-danger btn-sm" role="button" title="Supprimer" href="{% url 'topologie:del-stack' stack.pk %}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
{% acl_end %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
|
|
|
@ -24,11 +24,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
{% load acl %}
|
||||
|
||||
<div class="table-responsive">
|
||||
{% if switch_list.paginator %}
|
||||
{% include "pagination.html" with list=switch_list %}
|
||||
{% endif %}
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -72,8 +73,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if switch_list.paginator %}
|
||||
{% include "pagination.html" with list=switch_list %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -43,7 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<td>{{switch_bay.name}}</td>
|
||||
<td>{{switch_bay.building}}</td>
|
||||
<td>{{switch_bay.info}}</td>
|
||||
<td>{{switch_bay.switch_set.all |join:", "}}</td>
|
||||
<td>{% for switch in switch_bay.switch_set.all %}<a href="{% url 'topologie:index-port' switch.pk %}">{{switch }} </a>{% endfor %}</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'topologie:history' 'switchbay' switch_bay.pk %}">
|
||||
<i class="fa fa-history"></i>
|
||||
|
|
|
@ -29,7 +29,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
{% block title %}Switchs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Switchs</h2>
|
||||
<img id="zoom_01" src="/media/images/switchs.png" data-zoom-image="/media/images/switchs.png" width=100% />
|
||||
|
||||
<script type="text/javascript" src="/static/js/jquery.ez-plus.js"></script>
|
||||
|
||||
<script>
|
||||
$("#zoom_01").ezPlus({
|
||||
scrollZoom: true,
|
||||
zoomType: 'inner',
|
||||
cursor: 'crosshair'
|
||||
});
|
||||
</script>
|
||||
|
||||
<h2>Switchs</h2>
|
||||
{% can_create Switch %}
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:new-switch' %}"><i class="fa fa-plus"></i> Ajouter un switch</a>
|
||||
<hr>
|
||||
|
@ -38,4 +50,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -42,6 +42,7 @@ from django.contrib.auth.decorators import login_required
|
|||
from django.db import IntegrityError
|
||||
from django.db.models import ProtectedError, Prefetch
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||
|
||||
from users.views import form
|
||||
from re2o.utils import re2o_paginator, SortTable
|
||||
|
@ -88,6 +89,8 @@ from .forms import (
|
|||
EditBuildingForm
|
||||
)
|
||||
|
||||
from subprocess import Popen,PIPE
|
||||
|
||||
|
||||
@login_required
|
||||
@can_view_all(Switch)
|
||||
|
@ -349,6 +352,7 @@ def new_stack(request):
|
|||
if stack.is_valid():
|
||||
stack.save()
|
||||
messages.success(request, "Stack crée")
|
||||
return redirect(reverse('topologie:index-physical-grouping'))
|
||||
return form(
|
||||
{'topoform': stack, 'action_name': 'Créer'},
|
||||
'topologie/topo.html',
|
||||
|
@ -364,7 +368,7 @@ def edit_stack(request, stack, **_kwargs):
|
|||
if stack.is_valid():
|
||||
if stack.changed_data:
|
||||
stack.save()
|
||||
return redirect(reverse('topologie:index-physical-grouping'))
|
||||
return redirect(reverse('topologie:index-physical-grouping'))
|
||||
return form(
|
||||
{'topoform': stack, 'action_name': 'Editer'},
|
||||
'topologie/topo.html',
|
||||
|
@ -926,8 +930,103 @@ def del_constructor_switch(request, constructor_switch, **_kwargs):
|
|||
"de la supprimer (switch ou user)" % constructor_switch)
|
||||
)
|
||||
return redirect(reverse('topologie:index-model-switch'))
|
||||
return form(
|
||||
{'objet': constructor_switch, 'objet_name': 'Constructeur de switch'},
|
||||
'topologie/delete.html',
|
||||
request
|
||||
)
|
||||
return form({
|
||||
'objet': constructor_switch,
|
||||
'objet_name': 'Constructeur de switch'
|
||||
}, 'topologie/delete.html', request)
|
||||
|
||||
|
||||
def make_machine_graph():
|
||||
"""
|
||||
Crée le fichier dot et l'image du graph des Switchs
|
||||
"""
|
||||
#Syntaxe DOT temporaire, A mettre dans un template:
|
||||
lignes=['''digraph Switchs {
|
||||
node [
|
||||
fontname=Helvetica
|
||||
fontsize=8
|
||||
shape=plaintext]
|
||||
edge[arrowhead=odot,arrowtail=dot]''']
|
||||
node_fixe='''node [label=<
|
||||
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
|
||||
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4">
|
||||
<FONT FACE="Helvetica Bold" COLOR="white">
|
||||
{}
|
||||
</FONT></TD></TR>
|
||||
<TR><TD ALIGN="LEFT" BORDER="0">
|
||||
<FONT COLOR="#7B7B7B" >{}</FONT>
|
||||
</TD>
|
||||
<TD ALIGN="LEFT">
|
||||
<FONT COLOR="#7B7B7B" >{}</FONT>
|
||||
</TD></TR>
|
||||
<TR><TD ALIGN="LEFT" BORDER="0">
|
||||
<FONT COLOR="#7B7B7B" >{}</FONT>
|
||||
</TD>
|
||||
<TD ALIGN="LEFT">
|
||||
<FONT>{}</FONT>
|
||||
</TD></TR>'''
|
||||
node_ports='''<TR><TD ALIGN="LEFT" BORDER="0">
|
||||
<FONT COLOR="#7B7B7B" >{}</FONT>
|
||||
</TD>
|
||||
<TD ALIGN="LEFT">
|
||||
<FONT>{}</FONT>
|
||||
</TD></TR>'''
|
||||
cluster='''subgraph cluster_{} {{
|
||||
color=blue;
|
||||
label="Batiment {}";'''
|
||||
end_table='''</TABLE>
|
||||
>] \"{}_{}\" ;'''
|
||||
switch_alone='''{} [label=<
|
||||
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
|
||||
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4">
|
||||
<FONT FACE="Helvetica Bold" COLOR="white">
|
||||
{}
|
||||
</FONT></TD></TR>
|
||||
</TABLE>
|
||||
>]'''
|
||||
missing=[]
|
||||
detected=[]
|
||||
for sw in Switch.objects.all():
|
||||
if(sw not in detected):
|
||||
missing.append(sw)
|
||||
for building in Building.objects.all():
|
||||
lignes.append(cluster.format(len(lignes),building))
|
||||
for switch in Switch.objects.filter(switchbay__building=building):
|
||||
lignes.append(node_fixe.format(switch.main_interface().domain.name,"Modèle",switch.model,"Nombre de ports",switch.number))
|
||||
for p in switch.ports.all().filter(related__isnull=False):
|
||||
lignes.append(node_ports.format(p.port,p.related.switch.main_interface().domain.name))
|
||||
lignes.append(end_table.format(building.id,switch.id))
|
||||
lignes.append("}")
|
||||
while(missing!=[]):
|
||||
lignes,new_detected=recursive_switchs(missing[0].ports.all().filter(related=None).first(),None,lignes,[missing[0]])
|
||||
missing=[i for i in missing if i not in new_detected]
|
||||
detected+=new_detected
|
||||
for switch in Switch.objects.all().filter(switchbay__isnull=True).exclude(ports__related__isnull=False):
|
||||
lignes.append(switch_alone.format(switch.id,switch.main_interface().domain.name))
|
||||
lignes.append("}")
|
||||
fichier = open("media/images/switchs.dot","w")
|
||||
for ligne in lignes:
|
||||
fichier.write(ligne+"\n")
|
||||
fichier.close()
|
||||
unflatten = Popen(["unflatten","-l", "3", "media/images/switchs.dot"], stdout=PIPE)
|
||||
image = Popen(["dot", "-Tpng", "-o", "media/images/switchs.png"], stdin=unflatten.stdout, stdout=PIPE)
|
||||
|
||||
|
||||
def recursive_switchs(port_start, switch_before, lignes,detected):
|
||||
"""
|
||||
Parcour récursivement le switchs auquel appartient port_start pour trouver les ports suivants liés
|
||||
"""
|
||||
l_ports=port_start.switch.ports.filter(related__isnull=False)
|
||||
for port in l_ports:
|
||||
if port.related.switch!=switch_before and port.related.switch!=port.switch:
|
||||
links=[]
|
||||
for sw in [switch for switch in [port_start.switch,port.related.switch]]:
|
||||
if(sw not in detected):
|
||||
detected.append(sw)
|
||||
if(sw.switchbay.building):
|
||||
links.append("\"{}_{}\"".format(sw.switchbay.building.id,sw.id))
|
||||
else:
|
||||
links.append("\"{}\"".format(sw.id))
|
||||
lignes.append(links[0]+" -> "+links[1])
|
||||
lignes, detected = recursive_switchs(port.related, port_start.switch, lignes, detected)
|
||||
return (lignes, detected)
|
||||
|
|
Loading…
Reference in a new issue