+ {% can_edit estimate %}
+ {% include 'buttons/edit.html' with href='cotisations:edit-cost-estimate' id=estimate.id %}
+ {% acl_end %}
+ {% history_button estimate %}
+ {% include 'buttons/suppr.html' with href='cotisations:del-cost-estimate' id=estimate.id %}
+
+
+
+
+ {% trans "PDF" %}
+
+
+
+ {% endfor %}
+
+
+ {% if custom_invoice_list.paginator %}
+ {% include 'pagination.html' with list=custom_invoice_list %}
+ {% endif %}
+
diff --git a/cotisations/templates/cotisations/aff_cotisations.html b/cotisations/templates/cotisations/aff_cotisations.html
index 30de85dc..e27ae8c7 100644
--- a/cotisations/templates/cotisations/aff_cotisations.html
+++ b/cotisations/templates/cotisations/aff_cotisations.html
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if facture_list.paginator %}
-{% include 'pagination.html' with list=facture_list %}
+ {% include 'pagination.html' with list=facture_list %}
{% endif %}
@@ -48,7 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Date" as tr_date %}
{% include 'buttons/sort.html' with prefix='cotis' col='date' text=tr_date %}
-
+
{% trans "Invoice ID" as tr_invoice_id %}
{% include 'buttons/sort.html' with prefix='cotis' col='id' text=tr_invoice_id %}
@@ -63,33 +63,38 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{{ facture.prix_total }}
{{ facture.paiement }}
{{ facture.date }}
-
{{ facture.id }}
+
{{ facture.id }}
{% can_edit facture %}
- {% include 'buttons/edit.html' with href='cotisations:edit-facture' id=facture.id %}
+ {% include 'buttons/edit.html' with href='cotisations:edit-facture' id=facture.id %}
{% acl_else %}
{% trans "Controlled invoice" %}
{% acl_end %}
{% can_delete facture %}
- {% include 'buttons/suppr.html' with href='cotisations:del-facture' id=facture.id %}
+ {% include 'buttons/suppr.html' with href='cotisations:del-facture' id=facture.id %}
{% acl_end %}
- {% history_button facture %}
+ {% history_button facture %}
-{% if facture_list.paginator %}
-{% include 'pagination.html' with list=facture_list %}
-{% endif %}
+ {% if facture_list.paginator %}
+ {% include 'pagination.html' with list=facture_list %}
+ {% endif %}
diff --git a/cotisations/templates/cotisations/aff_custom_invoice.html b/cotisations/templates/cotisations/aff_custom_invoice.html
index 41984c2c..c1c5a396 100644
--- a/cotisations/templates/cotisations/aff_custom_invoice.html
+++ b/cotisations/templates/cotisations/aff_custom_invoice.html
@@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if custom_invoice_list.paginator %}
- {% include 'pagination.html' with list=custom_invoice_list %}
+ {% include 'pagination.html' with list=custom_invoice_list %}
{% endif %}
@@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Recipient" as tr_recip %}
- {% include 'buttons/sort.html' with prefix='invoice' col='user' text=tr_user %}
+ {% include 'buttons/sort.html' with prefix='invoice' col='user' text=tr_recip %}
{% trans "Designation" %}
{% trans "Total price" %}
@@ -51,7 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% include 'buttons/sort.html' with prefix='invoice' col='id' text=tr_invoice_id %}
- {% trans "Paid" as tr_invoice_paid%}
+ {% trans "Paid" as tr_invoice_paid %}
{% include 'buttons/sort.html' with prefix='invoice' col='paid' text=tr_invoice_paid %}
@@ -76,7 +76,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% acl_end %}
{% history_button invoice %}
- {% trans "PDF" %}
+ {% trans "PDF" %}
@@ -84,6 +84,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if custom_invoice_list.paginator %}
- {% include 'pagination.html' with list=custom_invoice_list %}
+ {% include 'pagination.html' with list=custom_invoice_list %}
{% endif %}
diff --git a/cotisations/templates/cotisations/aff_paiement.html b/cotisations/templates/cotisations/aff_paiement.html
index 633eb456..afb78b48 100644
--- a/cotisations/templates/cotisations/aff_paiement.html
+++ b/cotisations/templates/cotisations/aff_paiement.html
@@ -45,9 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
diff --git a/cotisations/templates/cotisations/control.html b/cotisations/templates/cotisations/control.html
index 6a4a5cca..5a18bd01 100644
--- a/cotisations/templates/cotisations/control.html
+++ b/cotisations/templates/cotisations/control.html
@@ -1,4 +1,4 @@
-{% extends "cotisations/sidebar.html" %}
+{% extends 'cotisations/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Invoice control and validation" %}
{% if facture_list.paginator %}
-{% include 'pagination.html' with list=facture_list %}
+ {% include 'pagination.html' with list=facture_list %}
{% endif %}
{% endblock %}
{% if facture_list.paginator %}
-{% include 'pagination.html' with list=facture_list %}
+ {% include 'pagination.html' with list=facture_list %}
{% endif %}
diff --git a/cotisations/templates/cotisations/delete.html b/cotisations/templates/cotisations/delete.html
index dc06e5a5..e6060d09 100644
--- a/cotisations/templates/cotisations/delete.html
+++ b/cotisations/templates/cotisations/delete.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'cotisations/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -36,7 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% blocktrans %}Warning: are you sure you really want to delete this {{ object_name }} object ( {{ objet }} )?{% endblocktrans %}
{% trans "Confirm" as tr_confirm %}
- {% bootstrap_button tr_confirm button_type='submit' icon='trash' %}
+ {% bootstrap_button tr_confirm button_type='submit' icon='trash' button_class='btn-danger' %}
{% endblock %}
diff --git a/cotisations/templates/cotisations/edit_facture.html b/cotisations/templates/cotisations/edit_facture.html
index 9ddcac8c..891f7476 100644
--- a/cotisations/templates/cotisations/edit_facture.html
+++ b/cotisations/templates/cotisations/edit_facture.html
@@ -1,4 +1,4 @@
-{% extends "cotisations/sidebar.html" %}
+{% extends 'cotisations/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -35,10 +35,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endblock %}
diff --git a/cotisations/templates/cotisations/email_subscription_accepted b/cotisations/templates/cotisations/email_subscription_accepted
new file mode 100644
index 00000000..58027cec
--- /dev/null
+++ b/cotisations/templates/cotisations/email_subscription_accepted
@@ -0,0 +1,22 @@
+Bonjour {{name}} !
+
+Nous vous informons que votre cotisation auprès de {{asso_name}} a été acceptée. Vous voilà donc membre de l'association.
+
+Vous trouverez en pièce jointe un reçu.
+
+Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}.
+
+À bientôt,
+L'équipe de {{asso_name}}.
+
+---
+
+Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}}.
+
+You will find with this email a subscription voucher.
+
+For any information, suggestion or problem, you can contact us via email at
+{{asso_email}}.
+
+Regards,
+The {{asso_name}} team.
diff --git a/cotisations/templates/cotisations/facture.html b/cotisations/templates/cotisations/facture.html
index 4f905160..65b05199 100644
--- a/cotisations/templates/cotisations/facture.html
+++ b/cotisations/templates/cotisations/facture.html
@@ -1,4 +1,4 @@
-{% extends "cotisations/sidebar.html" %}
+{% extends 'cotisations/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if title %}
{% can_create CustomInvoice %}
-{% include "buttons/add.html" with href='cotisations:new-custom-invoice'%}
+{% include 'buttons/add.html' with href='cotisations:new-custom-invoice'%}
{% acl_end %}
{% include 'cotisations/aff_custom_invoice.html' with custom_invoice_list=custom_invoice_list %}
{% endblock %}
diff --git a/cotisations/templates/cotisations/index_paiement.html b/cotisations/templates/cotisations/index_paiement.html
index f4908d02..09b7e033 100644
--- a/cotisations/templates/cotisations/index_paiement.html
+++ b/cotisations/templates/cotisations/index_paiement.html
@@ -1,4 +1,4 @@
-{% extends "cotisations/sidebar.html" %}
+{% extends 'cotisations/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
diff --git a/cotisations/templates/cotisations/payment.html b/cotisations/templates/cotisations/payment.html
index 997168fd..ceb8db6f 100644
--- a/cotisations/templates/cotisations/payment.html
+++ b/cotisations/templates/cotisations/payment.html
@@ -1,4 +1,4 @@
-{% extends "cotisations/sidebar.html" %}
+{% extends 'cotisations/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -40,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% bootstrap_form form %}
{% endif %}
{% trans "Pay" as tr_pay %}
- {% bootstrap_button tr_pay button_type='submit' icon='piggy-bank' %}
+ {% bootstrap_button tr_pay button_type='submit' icon='piggy-bank' button_class='btn-success' %}
{% endblock %}
diff --git a/cotisations/templates/cotisations/sidebar.html b/cotisations/templates/cotisations/sidebar.html
index 4f077fad..608f95c2 100644
--- a/cotisations/templates/cotisations/sidebar.html
+++ b/cotisations/templates/cotisations/sidebar.html
@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends 'base.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -28,35 +28,40 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block sidebar %}
{% can_create CustomInvoice %}
-
+
{% trans "Create an invoice" %}
-
+
{% trans "Control the invoices" %}
{% acl_end %}
{% can_view_all Facture %}
-
+
{% trans "Invoices" %}
{% acl_end %}
{% can_view_all CustomInvoice %}
-
+
{% trans "Custom invoices" %}
{% acl_end %}
+ {% can_view_all CostEstimate %}
+
+ {% trans "Cost estimates" %}
+
+ {% acl_end %}
{% can_view_all Article %}
-
+
{% trans "Available articles" %}
{% acl_end %}
{% can_view_all Banque %}
-
+
{% trans "Banks" %}
{% acl_end %}
{% can_view_all Paiement %}
-
+
{% trans "Payment methods" %}
{% acl_end %}
diff --git a/cotisations/templates/cotisations/voucher.tex b/cotisations/templates/cotisations/voucher.tex
new file mode 100644
index 00000000..aeebc187
--- /dev/null
+++ b/cotisations/templates/cotisations/voucher.tex
@@ -0,0 +1,87 @@
+{% load i18n %}
+{% language 'fr' %}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Invoice Template
+% LaTeX Template
+% Version 1.0 (3/11/12)
+%% This template has been downloaded from:
+% http://www.LaTeXTemplates.com
+%
+% Original author:
+% Trey Hunner (http://www.treyhunner.com/)
+%
+% License:
+% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
+%
+% Important note:
+% This template requires the invoice.cls file to be in the same directory as
+% the .tex file. The invoice.cls file provides the style used for structuring the
+% document.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%----------------------------------------------------------------------------------------
+% DOCUMENT CONFIGURATION
+%----------------------------------------------------------------------------------------
+
+\documentclass[12pt]{article} % Use the custom invoice class (invoice.cls)
+\usepackage[utf8]{inputenc}
+\usepackage[letterpaper,hmargin=0.79in,vmargin=0.79in]{geometry}
+\usepackage{longtable}
+\usepackage{graphicx}
+\usepackage{tabularx}
+\usepackage{eurosym}
+\usepackage{multicol}
+
+\pagestyle{empty} % No page numbers
+
+\linespread{1.5}
+
+\newcommand{\doublehline}{\noalign{\hrule height 1pt}}
+\setlength{\parindent}{0cm}
+
+
+\begin{document}
+
+ %----------------------------------------------------------------------------------------
+ % HEADING SECTION
+ %----------------------------------------------------------------------------------------
+ \begin{center}
+ {\Huge\bf Reçu d'adhésion \\ {{asso_name|safe}} } % Company providing the invoice
+ \end{center}
+
+ \bigskip
+ \hrule
+ \bigskip
+
+ \vfill
+
+ Je sousigné, {{pres_name|safe}}, déclare par la présente avoir reçu le bulletin d'adhésion de:
+
+ \begin{center}
+ \setlength{\tabcolsep}{10pt} % Make table columns tighter, usefull for postionning
+ \begin{tabular}{r l r l}
+ {\bf Prénom :}~ & {{firstname|safe}} & {% if phone %}{\bf Téléphone :}~ & {{phone}}{% else %} & {% endif %} \\
+ {\bf Nom :}~ & {{lastname|safe}} & {\bf Mail :}~ & {{email|safe}} \\
+ \end{tabular}
+ \end{center}
+ \bigskip
+
+ ainsi que sa cotisation.
+
+ Le postulant, déclare reconnaître l'objet de l'association, et en a accepté les statuts ainsi que le règlement intérieur qui sont mis à sa disposition dans les locaux de l'association. L'adhésion du membre sus-nommé est ainsi validée. Ce reçu confirme la qualité de membre du postulant, et ouvre droit à la participation à l'assemblée générale de l'association jusqu'au {{date_end|date:"d F Y"}}.
+
+ \bigskip
+
+ Validé électroniquement par {{pres_name|safe}}, le {{date_begin|date:"d/m/Y"}}.
+
+ \vfill
+ \hrule
+ \smallskip
+ \footnotesize
+ Les informations recueillies sont nécessaires pour votre adhésion. Conformément à la loi "Informatique et Libertés" du 6 janvier 1978, vous disposez d'un droit d'accès et de rectification aux données personnelles vous concernant. Pour l'exercer, adressez-vous au secrétariat de l'association.
+
+
+\end{document}
+{% endlanguage %}
diff --git a/cotisations/tex.py b/cotisations/tex.py
index 0ee45bdb..1ab964ba 100644
--- a/cotisations/tex.py
+++ b/cotisations/tex.py
@@ -1,4 +1,4 @@
-# coding: utf-8
+# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
@@ -31,11 +31,16 @@ from subprocess import Popen, PIPE
import os
from datetime import datetime
+from django.db import models
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
from django.conf import settings
from django.utils.text import slugify
+from django.utils.translation import ugettext_lazy as _
+
+from re2o.mixins import AclMixin, RevMixin
+from preferences.models import CotisationsOption
TEMP_PREFIX = getattr(settings, 'TEX_TEMP_PREFIX', 'render_tex-')
@@ -48,15 +53,40 @@ def render_invoice(_request, ctx={}):
Render an invoice using some available information such as the current
date, the user, the articles, the prices, ...
"""
+ options, _ = CotisationsOption.objects.get_or_create()
+ is_estimate = ctx.get('is_estimate', False)
filename = '_'.join([
- 'invoice',
+ 'cost_estimate' if is_estimate else 'invoice',
slugify(ctx.get('asso_name', "")),
slugify(ctx.get('recipient_name', "")),
str(ctx.get('DATE', datetime.now()).year),
str(ctx.get('DATE', datetime.now()).month),
str(ctx.get('DATE', datetime.now()).day),
])
- r = render_tex(_request, 'cotisations/factures.tex', ctx)
+ templatename = options.invoice_template.template.name.split('/')[-1]
+ r = render_tex(_request, templatename, ctx)
+ r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format(
+ name=filename
+ )
+ return r
+
+
+def render_voucher(_request, ctx={}):
+ """
+ Render a subscribtion voucher.
+ """
+ options, _ = CotisationsOption.objects.get_or_create()
+ filename = '_'.join([
+ 'voucher',
+ slugify(ctx.get('asso_name', "")),
+ slugify(ctx.get('firstname', "")),
+ slugify(ctx.get('lastname', "")),
+ str(ctx.get('date_begin', datetime.now()).year),
+ str(ctx.get('date_begin', datetime.now()).month),
+ str(ctx.get('date_begin', datetime.now()).day),
+ ])
+ templatename = options.voucher_template.template.name.split('/')[-1]
+ r = render_tex(_request, templatename, ctx)
r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format(
name=filename
)
@@ -81,18 +111,33 @@ def create_pdf(template, ctx={}):
with tempfile.TemporaryDirectory() as tempdir:
for _ in range(2):
- process = Popen(
- ['pdflatex', '-output-directory', tempdir],
- stdin=PIPE,
- stdout=PIPE,
- )
- process.communicate(rendered_tpl)
+ with open("/var/www/re2o/out.log", "w") as f:
+ process = Popen(
+ ['pdflatex', '-output-directory', tempdir],
+ stdin=PIPE,
+ stdout=f,#PIPE,
+ )
+ process.communicate(rendered_tpl)
with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f:
pdf = f.read()
return pdf
+def escape_chars(string):
+ """Escape the '%' and the '€' signs to avoid messing with LaTeX"""
+ if not isinstance(string, str):
+ return string
+ mapping = (
+ ('€', r'\euro'),
+ ('%', r'\%'),
+ )
+ r = str(string)
+ for k, v in mapping:
+ r = r.replace(k, v)
+ return r
+
+
def render_tex(_request, template, ctx={}):
"""Creates a PDF from a LaTex templates using pdflatex.
diff --git a/cotisations/urls.py b/cotisations/urls.py
index edc448fe..0c7256f7 100644
--- a/cotisations/urls.py
+++ b/cotisations/urls.py
@@ -51,11 +51,46 @@ urlpatterns = [
views.facture_pdf,
name='facture-pdf'
),
+ url(
+ r'^voucher_pdf/(?P[0-9]+)$',
+ views.voucher_pdf,
+ name='voucher-pdf'
+ ),
+ url(
+ r'^new_cost_estimate/$',
+ views.new_cost_estimate,
+ name='new-cost-estimate'
+ ),
+ url(
+ r'^index_cost_estimate/$',
+ views.index_cost_estimate,
+ name='index-cost-estimate'
+ ),
+ url(
+ r'^cost_estimate_pdf/(?P[0-9]+)$',
+ views.cost_estimate_pdf,
+ name='cost-estimate-pdf',
+ ),
url(
r'^index_custom_invoice/$',
views.index_custom_invoice,
name='index-custom-invoice'
),
+ url(
+ r'^edit_cost_estimate/(?P[0-9]+)$',
+ views.edit_cost_estimate,
+ name='edit-cost-estimate'
+ ),
+ url(
+ r'^cost_estimate_to_invoice/(?P[0-9]+)$',
+ views.cost_estimate_to_invoice,
+ name='cost-estimate-to-invoice'
+ ),
+ url(
+ r'^del_cost_estimate/(?P[0-9]+)$',
+ views.del_cost_estimate,
+ name='del-cost-estimate'
+ ),
url(
r'^new_custom_invoice/$',
views.new_custom_invoice,
@@ -146,5 +181,5 @@ urlpatterns = [
views.control,
name='control'
),
- url(r'^$', views.index, name='index'),
+ url(r'^$', views.index, name='index'),
] + payment_methods.urls.urlpatterns
diff --git a/cotisations/utils.py b/cotisations/utils.py
index 0211dd40..4715338b 100644
--- a/cotisations/utils.py
+++ b/cotisations/utils.py
@@ -25,7 +25,7 @@ from django.template.loader import get_template
from django.core.mail import EmailMessage
from .tex import create_pdf
-from preferences.models import AssoOption, GeneralOption
+from preferences.models import AssoOption, GeneralOption, CotisationsOption
from re2o.settings import LOGO_PATH
from re2o import settings
@@ -89,7 +89,42 @@ def send_mail_invoice(invoice):
'Votre facture / Your invoice',
template.render(ctx),
GeneralOption.get_cached_value('email_from'),
- [invoice.user.email],
+ [invoice.user.get_mail],
attachments=[('invoice.pdf', pdf, 'application/pdf')]
)
mail.send()
+
+
+def send_mail_voucher(invoice):
+ """Creates a voucher from an invoice and sends it by email to the client"""
+ ctx = {
+ 'asso_name': AssoOption.get_cached_value('name'),
+ 'pres_name': AssoOption.get_cached_value('pres_name'),
+ 'firstname': invoice.user.name,
+ 'lastname': invoice.user.surname,
+ 'email': invoice.user.email,
+ 'phone': invoice.user.telephone,
+ 'date_end': invoice.get_subscription().latest('date_end').date_end,
+ 'date_begin': invoice.get_subscription().earliest('date_start').date_start
+ }
+ templatename = CotisationsOption.get_cached_value('voucher_template').template.name.split('/')[-1]
+ pdf = create_pdf(templatename, ctx)
+ template = get_template('cotisations/email_subscription_accepted')
+
+ ctx = {
+ 'name': "{} {}".format(
+ invoice.user.name,
+ invoice.user.surname
+ ),
+ 'asso_email': AssoOption.get_cached_value('contact'),
+ 'asso_name': AssoOption.get_cached_value('name')
+ }
+
+ mail = EmailMessage(
+ 'Votre reçu / Your voucher',
+ template.render(ctx),
+ GeneralOption.get_cached_value('email_from'),
+ [invoice.user.get_mail],
+ attachments=[('voucher.pdf', pdf, 'application/pdf')]
+ )
+ mail.send()
diff --git a/cotisations/views.py b/cotisations/views.py
index a4a35825..b6d5a8a6 100644
--- a/cotisations/views.py
+++ b/cotisations/views.py
@@ -47,7 +47,10 @@ from users.models import User
from re2o.settings import LOGO_PATH
from re2o import settings
from re2o.views import form
-from re2o.utils import SortTable, re2o_paginator
+from re2o.base import (
+ SortTable,
+ re2o_paginator,
+)
from re2o.acl import (
can_create,
can_edit,
@@ -65,7 +68,8 @@ from .models import (
Paiement,
Banque,
CustomInvoice,
- BaseInvoice
+ BaseInvoice,
+ CostEstimate,
)
from .forms import (
FactureForm,
@@ -77,11 +81,13 @@ from .forms import (
DelBanqueForm,
SelectArticleForm,
RechargeForm,
- CustomInvoiceForm
+ CustomInvoiceForm,
+ DiscountForm,
+ CostEstimateForm,
)
-from .tex import render_invoice
+from .tex import render_invoice, render_voucher, escape_chars
from .payment_methods.forms import payment_method_factory
-from .utils import find_payment_method, send_mail_invoice
+from .utils import find_payment_method
@login_required
@@ -148,8 +154,6 @@ def new_facture(request, user, userid):
p.facture = new_invoice_instance
p.save()
- send_mail_invoice(new_invoice_instance)
-
return new_invoice_instance.paiement.end_payment(
new_invoice_instance,
request
@@ -171,13 +175,65 @@ def new_facture(request, user, userid):
'articlesformset': article_formset,
'articlelist': article_list,
'balance': balance,
- 'action_name': _('Create'),
+ 'action_name': _('Confirm'),
},
'cotisations/facture.html', request
)
-# TODO : change facture to invoice
+@login_required
+@can_create(CostEstimate)
+def new_cost_estimate(request):
+ """
+ View used to generate a custom invoice. It's mainly used to
+ get invoices that are not taken into account, for the administrative
+ point of view.
+ """
+ # The template needs the list of articles (for the JS part)
+ articles = Article.objects.filter(
+ Q(type_user='All') | Q(type_user=request.user.class_name)
+ )
+ # Building the invocie form and the article formset
+ cost_estimate_form = CostEstimateForm(request.POST or None)
+
+ articles_formset = formset_factory(SelectArticleForm)(
+ request.POST or None,
+ form_kwargs={'user': request.user}
+ )
+ discount_form = DiscountForm(request.POST or None)
+
+ if cost_estimate_form.is_valid() and articles_formset.is_valid() and discount_form.is_valid():
+ cost_estimate_instance = cost_estimate_form.save()
+ for art_item in articles_formset:
+ if art_item.cleaned_data:
+ article = art_item.cleaned_data['article']
+ quantity = art_item.cleaned_data['quantity']
+ Vente.objects.create(
+ facture=cost_estimate_instance,
+ name=article.name,
+ prix=article.prix,
+ type_cotisation=article.type_cotisation,
+ duration=article.duration,
+ number=quantity
+ )
+ discount_form.apply_to_invoice(cost_estimate_instance)
+
+ messages.success(
+ request,
+ _("The cost estimate was created.")
+ )
+ return redirect(reverse('cotisations:index-cost-estimate'))
+
+ return form({
+ 'factureform': cost_estimate_form,
+ 'action_name': _("Confirm"),
+ 'articlesformset': articles_formset,
+ 'articlelist': articles,
+ 'discount_form': discount_form,
+ 'title': _("Cost estimate"),
+ }, 'cotisations/facture.html', request)
+
+
@login_required
@can_create(CustomInvoice)
def new_custom_invoice(request):
@@ -193,12 +249,13 @@ def new_custom_invoice(request):
# Building the invocie form and the article formset
invoice_form = CustomInvoiceForm(request.POST or None)
- article_formset = formset_factory(SelectArticleForm)(
+ articles_formset = formset_factory(SelectArticleForm)(
request.POST or None,
- form_kwargs={'user': request.user, 'target_user': user}
+ form_kwargs={'user': request.user}
)
+ discount_form = DiscountForm(request.POST or None)
- if invoice_form.is_valid() and articles_formset.is_valid():
+ if invoice_form.is_valid() and articles_formset.is_valid() and discount_form.is_valid():
new_invoice_instance = invoice_form.save()
for art_item in articles_formset:
if art_item.cleaned_data:
@@ -212,18 +269,19 @@ def new_custom_invoice(request):
duration=article.duration,
number=quantity
)
+ discount_form.apply_to_invoice(new_invoice_instance)
messages.success(
request,
_("The custom invoice was created.")
)
return redirect(reverse('cotisations:index-custom-invoice'))
-
return form({
'factureform': invoice_form,
- 'action_name': _("Create"),
+ 'action_name': _("Confirm"),
'articlesformset': articles_formset,
- 'articlelist': articles
+ 'articlelist': articles,
+ 'discount_form': discount_form
}, 'cotisations/facture.html', request)
@@ -266,7 +324,8 @@ def facture_pdf(request, facture, **_kwargs):
'siret': AssoOption.get_cached_value('siret'),
'email': AssoOption.get_cached_value('contact'),
'phone': AssoOption.get_cached_value('telephone'),
- 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
+ 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH),
+ 'payment_method': facture.paiement.moyen,
})
@@ -331,6 +390,55 @@ def del_facture(request, facture, **_kwargs):
}, 'cotisations/delete.html', request)
+@login_required
+@can_edit(CostEstimate)
+def edit_cost_estimate(request, invoice, **kwargs):
+ # Building the invocie form and the article formset
+ invoice_form = CostEstimateForm(
+ request.POST or None,
+ instance=invoice
+ )
+ purchases_objects = Vente.objects.filter(facture=invoice)
+ purchase_form_set = modelformset_factory(
+ Vente,
+ fields=('name', 'number'),
+ extra=0,
+ max_num=len(purchases_objects)
+ )
+ purchase_form = purchase_form_set(
+ request.POST or None,
+ queryset=purchases_objects
+ )
+ if invoice_form.is_valid() and purchase_form.is_valid():
+ if invoice_form.changed_data:
+ invoice_form.save()
+ purchase_form.save()
+ messages.success(
+ request,
+ _("The cost estimate was edited.")
+ )
+ return redirect(reverse('cotisations:index-cost-estimate'))
+
+ return form({
+ 'factureform': invoice_form,
+ 'venteform': purchase_form,
+ 'title': _("Edit cost estimate")
+ }, 'cotisations/edit_facture.html', request)
+
+
+@login_required
+@can_edit(CostEstimate)
+@can_create(CustomInvoice)
+def cost_estimate_to_invoice(request, cost_estimate, **_kwargs):
+ """Create a custom invoice from a cos estimate"""
+ cost_estimate.create_invoice()
+ messages.success(
+ request,
+ _("An invoice was successfully created from your cost estimate.")
+ )
+ return redirect(reverse('cotisations:index-custom-invoice'))
+
+
@login_required
@can_edit(CustomInvoice)
def edit_custom_invoice(request, invoice, **kwargs):
@@ -367,22 +475,21 @@ def edit_custom_invoice(request, invoice, **kwargs):
@login_required
-@can_view(CustomInvoice)
-def custom_invoice_pdf(request, invoice, **_kwargs):
+@can_view(CostEstimate)
+def cost_estimate_pdf(request, invoice, **_kwargs):
"""
- View used to generate a PDF file from an existing invoice in database
+ View used to generate a PDF file from an existing cost estimate in database
Creates a line for each Purchase (thus article sold) and generate the
invoice with the total price, the payment method, the address and the
legal information for the user.
"""
- # TODO : change vente to purchase
purchases_objects = Vente.objects.all().filter(facture=invoice)
# Get the article list and build an list out of it
# contiaining (article_name, article_price, quantity, total_price)
purchases_info = []
for purchase in purchases_objects:
purchases_info.append({
- 'name': purchase.name,
+ 'name': escape_chars(purchase.name),
'price': purchase.prix,
'quantity': purchase.number,
'total_price': purchase.prix_total
@@ -401,11 +508,74 @@ def custom_invoice_pdf(request, invoice, **_kwargs):
'siret': AssoOption.get_cached_value('siret'),
'email': AssoOption.get_cached_value('contact'),
'phone': AssoOption.get_cached_value('telephone'),
- 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
+ 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH),
+ 'payment_method': invoice.payment,
+ 'remark': invoice.remark,
+ 'end_validity': invoice.date + invoice.validity,
+ 'is_estimate': True,
+ })
+
+
+@login_required
+@can_delete(CostEstimate)
+def del_cost_estimate(request, estimate, **_kwargs):
+ """
+ View used to delete an existing invocie.
+ """
+ if request.method == "POST":
+ estimate.delete()
+ messages.success(
+ request,
+ _("The cost estimate was deleted.")
+ )
+ return redirect(reverse('cotisations:index-cost-estimate'))
+ return form({
+ 'objet': estimate,
+ 'objet_name': _("Cost estimate")
+ }, 'cotisations/delete.html', request)
+
+
+@login_required
+@can_view(CustomInvoice)
+def custom_invoice_pdf(request, invoice, **_kwargs):
+ """
+ View used to generate a PDF file from an existing invoice in database
+ Creates a line for each Purchase (thus article sold) and generate the
+ invoice with the total price, the payment method, the address and the
+ legal information for the user.
+ """
+ # TODO : change vente to purchase
+ purchases_objects = Vente.objects.all().filter(facture=invoice)
+ # Get the article list and build an list out of it
+ # contiaining (article_name, article_price, quantity, total_price)
+ purchases_info = []
+ for purchase in purchases_objects:
+ purchases_info.append({
+ 'name': escape_chars(purchase.name),
+ 'price': purchase.prix,
+ 'quantity': purchase.number,
+ 'total_price': purchase.prix_total
+ })
+ return render_invoice(request, {
+ 'paid': invoice.paid,
+ 'fid': invoice.id,
+ 'DATE': invoice.date,
+ 'recipient_name': invoice.recipient,
+ 'address': invoice.address,
+ 'article': purchases_info,
+ 'total': invoice.prix_total(),
+ 'asso_name': AssoOption.get_cached_value('name'),
+ 'line1': AssoOption.get_cached_value('adresse1'),
+ 'line2': AssoOption.get_cached_value('adresse2'),
+ 'siret': AssoOption.get_cached_value('siret'),
+ 'email': AssoOption.get_cached_value('contact'),
+ 'phone': AssoOption.get_cached_value('telephone'),
+ 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH),
+ 'payment_method': invoice.payment,
+ 'remark': invoice.remark,
})
-# TODO : change facture to invoice
@login_required
@can_delete(CustomInvoice)
def del_custom_invoice(request, invoice, **_kwargs):
@@ -550,7 +720,7 @@ def edit_paiement(request, paiement_instance, **_kwargs):
if payment_method is not None:
payment_method.save()
messages.success(
- request,_("The payment method was edited.")
+ request, _("The payment method was edited.")
)
return redirect(reverse('cotisations:index-paiement'))
return form({
@@ -663,8 +833,8 @@ def del_banque(request, instances):
except ProtectedError:
messages.error(
request,
- _("The bank %(bank_name)s can't be deleted \
- because there are invoices using it.") % {
+ _("The bank %(bank_name)s can't be deleted because there"
+ " are invoices using it.") % {
'bank_name': bank_del
}
)
@@ -756,12 +926,36 @@ def index_banque(request):
})
+@login_required
+@can_view_all(CustomInvoice)
+def index_cost_estimate(request):
+ """View used to display every custom invoice."""
+ pagination_number = GeneralOption.get_cached_value('pagination_number')
+ cost_estimate_list = CostEstimate.objects.prefetch_related('vente_set')
+ cost_estimate_list = SortTable.sort(
+ cost_estimate_list,
+ request.GET.get('col'),
+ request.GET.get('order'),
+ SortTable.COTISATIONS_CUSTOM
+ )
+ cost_estimate_list = re2o_paginator(
+ request,
+ cost_estimate_list,
+ pagination_number,
+ )
+ return render(request, 'cotisations/index_cost_estimate.html', {
+ 'cost_estimate_list': cost_estimate_list
+ })
+
+
@login_required
@can_view_all(CustomInvoice)
def index_custom_invoice(request):
"""View used to display every custom invoice."""
pagination_number = GeneralOption.get_cached_value('pagination_number')
- custom_invoice_list = CustomInvoice.objects.prefetch_related('vente_set')
+ cost_estimate_ids = [i for i, in CostEstimate.objects.values_list('id')]
+ custom_invoice_list = CustomInvoice.objects.prefetch_related(
+ 'vente_set').exclude(id__in=cost_estimate_ids)
custom_invoice_list = SortTable.sort(
custom_invoice_list,
request.GET.get('col'),
@@ -827,7 +1021,8 @@ def credit_solde(request, user, **_kwargs):
kwargs={'userid': user.id}
))
- refill_form = RechargeForm(request.POST or None, user=user, user_source=request.user)
+ refill_form = RechargeForm(
+ request.POST or None, user=user, user_source=request.user)
if refill_form.is_valid():
price = refill_form.cleaned_data['value']
invoice = Facture(user=user)
@@ -839,7 +1034,6 @@ def credit_solde(request, user, **_kwargs):
else:
price_ok = True
if price_ok:
- invoice.valid = True
invoice.save()
Vente.objects.create(
facture=invoice,
@@ -848,8 +1042,6 @@ def credit_solde(request, user, **_kwargs):
number=1
)
- send_mail_invoice(invoice)
-
return invoice.paiement.end_payment(invoice, request)
p = get_object_or_404(Paiement, is_balance=True)
return form({
@@ -857,6 +1049,32 @@ def credit_solde(request, user, **_kwargs):
'balance': user.solde,
'title': _("Refill your balance"),
'action_name': _("Pay"),
- 'max_balance': p.payment_method.maximum_balance,
+ 'max_balance': find_payment_method(p).maximum_balance,
}, 'cotisations/facture.html', request)
+
+@login_required
+@can_view(Facture)
+def voucher_pdf(request, invoice, **_kwargs):
+ """
+ View used to generate a PDF file from a controlled invoice
+ Creates a line for each Purchase (thus article sold) and generate the
+ invoice with the total price, the payment method, the address and the
+ legal information for the user.
+ """
+ if not invoice.control:
+ messages.error(
+ request,
+ _("Could not find a voucher for that invoice.")
+ )
+ return redirect(reverse('cotisations:index'))
+ return render_voucher(request, {
+ 'asso_name': AssoOption.get_cached_value('name'),
+ 'pres_name': AssoOption.get_cached_value('pres_name'),
+ 'firstname': invoice.user.name,
+ 'lastname': invoice.user.surname,
+ 'email': invoice.user.email,
+ 'phone': invoice.user.telephone,
+ 'date_end': invoice.get_subscription().latest('date_end').date_end,
+ 'date_begin': invoice.date
+ })
diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py
index afa834b0..54364dc1 100644
--- a/freeradius_utils/auth.py
+++ b/freeradius_utils/auth.py
@@ -38,6 +38,7 @@ Inspiré du travail de Daniel Stan au Crans
import os
import sys
import logging
+import traceback
import radiusd # Module magique freeradius (radiusd.py is dummy)
from django.core.wsgi import get_wsgi_application
@@ -57,14 +58,9 @@ application = get_wsgi_application()
from machines.models import Interface, IpList, Nas, Domain
from topologie.models import Port, Switch
from users.models import User
-from preferences.models import OptionalTopologie
+from preferences.models import RadiusOption
-options, created = OptionalTopologie.objects.get_or_create()
-VLAN_NOK = options.vlan_decision_nok.vlan_id
-VLAN_OK = options.vlan_decision_ok.vlan_id
-RADIUS_POLICY = options.radius_general_policy
-
#: Serveur radius de test (pas la prod)
TEST_SERVER = bool(os.getenv('DBG_FREERADIUS', False))
@@ -81,7 +77,7 @@ class RadiusdHandler(logging.Handler):
rad_sig = radiusd.L_INFO
else:
rad_sig = radiusd.L_DBG
- radiusd.radlog(rad_sig, record.msg)
+ radiusd.radlog(rad_sig, record.msg.encode('utf-8'))
# Initialisation d'un logger (pour logguer unifié)
@@ -122,7 +118,8 @@ def radius_event(fun):
return fun(data)
except Exception as err:
logger.error('Failed %r on data %r' % (err, auth_data))
- raise
+ logger.debug('Function %r, Traceback: %s' % (fun, repr(traceback.format_stack())))
+ return radiusd.RLM_MODULE_FAIL
return new_f
@@ -194,12 +191,12 @@ def post_auth(data):
nas_instance = find_nas_from_request(nas)
# Toutes les reuquètes non proxifiées
if not nas_instance:
- logger.info(u"Requète proxifiée, nas inconnu".encode('utf-8'))
+ logger.info(u"Requete proxifiee, nas inconnu".encode('utf-8'))
return radiusd.RLM_MODULE_OK
nas_type = Nas.objects.filter(nas_type=nas_instance.type).first()
if not nas_type:
logger.info(
- u"Type de nas non enregistré dans la bdd!".encode('utf-8')
+ u"Type de nas non enregistre dans la bdd!".encode('utf-8')
)
return radiusd.RLM_MODULE_OK
@@ -227,27 +224,37 @@ def post_auth(data):
# On récupère le numéro du port sur l'output de freeradius.
# La ligne suivante fonctionne pour cisco, HP et Juniper
port = port.split(".")[0].split('/')[-1][-2:]
- out = decide_vlan_and_register_switch(nas_machine, nas_type, port, mac)
- sw_name, room, reason, vlan_id = out
+ out = decide_vlan_switch(nas_machine, nas_type, port, mac)
+ sw_name, room, reason, vlan_id, decision = out
- log_message = '(fil) %s -> %s [%s%s]' % (
- sw_name + u":" + port + u"/" + str(room),
- mac,
- vlan_id,
- (reason and u': ' + reason).encode('utf-8')
- )
- logger.info(log_message)
+ if decision:
+ log_message = '(fil) %s -> %s [%s%s]' % (
+ sw_name + u":" + port + u"/" + str(room),
+ mac,
+ vlan_id,
+ (reason and u': ' + reason).encode('utf-8')
+ )
+ logger.info(log_message)
- # Filaire
- return (
- radiusd.RLM_MODULE_UPDATED,
- (
- ("Tunnel-Type", "VLAN"),
- ("Tunnel-Medium-Type", "IEEE-802"),
- ("Tunnel-Private-Group-Id", '%d' % int(vlan_id)),
- ),
- ()
- )
+ # Filaire
+ return (
+ radiusd.RLM_MODULE_UPDATED,
+ (
+ ("Tunnel-Type", "VLAN"),
+ ("Tunnel-Medium-Type", "IEEE-802"),
+ ("Tunnel-Private-Group-Id", '%d' % int(vlan_id)),
+ ),
+ ()
+ )
+ else:
+ log_message = '(fil) %s -> %s [Reject:%s]' % (
+ sw_name + u":" + port + u"/" + str(room),
+ mac,
+ (reason and u': ' + reason).encode('utf-8')
+ )
+ logger.info(log_message)
+
+ return radiusd.RLM_MODULE_REJECT
else:
return radiusd.RLM_MODULE_OK
@@ -284,19 +291,19 @@ def check_user_machine_and_register(nas_type, username, mac_address):
Renvoie le mot de passe ntlm de l'user si tout est ok
Utilise pour les authentifications en 802.1X"""
interface = Interface.objects.filter(mac_address=mac_address).first()
- user = User.objects.filter(pseudo=username).first()
+ user = User.objects.filter(pseudo__iexact=username).first()
if not user:
return (False, u"User inconnu", '')
if not user.has_access():
- return (False, u"Adhérent non cotisant", '')
+ return (False, u"Adherent non cotisant", '')
if interface:
if interface.machine.user != user:
return (False,
- u"Machine enregistrée sur le compte d'un autre "
+ u"Machine enregistree sur le compte d'un autre "
"user...",
'')
elif not interface.is_active:
- return (False, u"Machine desactivée", '')
+ return (False, u"Machine desactivee", '')
elif not interface.ipv4:
interface.assign_ipv4()
return (True, u"Ok, Reassignation de l'ipv4", user.pwd_ntlm)
@@ -317,36 +324,51 @@ def check_user_machine_and_register(nas_type, username, mac_address):
return (False, u"Machine inconnue", '')
-def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
- mac_address):
+def decide_vlan_switch(nas_machine, nas_type, port_number,
+ mac_address):
"""Fonction de placement vlan pour un switch en radius filaire auth par
mac.
Plusieurs modes :
- - nas inconnu, port inconnu : on place sur le vlan par defaut VLAN_OK
- - pas de radius sur le port : VLAN_OK
- - bloq : VLAN_NOK
- - force : placement sur le vlan indiqué dans la bdd
- - mode strict :
- - pas de chambre associée : VLAN_NOK
- - pas d'utilisateur dans la chambre : VLAN_NOK
- - cotisation non à jour : VLAN_NOK
- - sinon passe à common (ci-dessous)
- - mode common :
- - interface connue (macaddress):
- - utilisateur proprio non cotisant ou banni : VLAN_NOK
- - user à jour : VLAN_OK
- - interface inconnue :
- - register mac désactivé : VLAN_NOK
- - register mac activé :
- - dans la chambre associé au port, pas d'user ou non à
- jour : VLAN_NOK
- - user à jour, autocapture de la mac et VLAN_OK
+ - tous les modes:
+ - nas inconnu: VLAN_OK
+ - port inconnu: Politique définie dans RadiusOption
+ - pas de radius sur le port: VLAN_OK
+ - force: placement sur le vlan indiqué dans la bdd
+ - mode strict:
+ - pas de chambre associée: Politique définie
+ dans RadiusOption
+ - pas d'utilisateur dans la chambre : Rejet
+ (redirection web si disponible)
+ - utilisateur de la chambre banni ou désactivé : Rejet
+ (redirection web si disponible)
+ - utilisateur de la chambre non cotisant et non whiteslist:
+ Politique définie dans RadiusOption
+
+ - sinon passe à common (ci-dessous)
+ - mode common :
+ - interface connue (macaddress):
+ - utilisateur proprio non cotisant / machine désactivée:
+ Politique définie dans RadiusOption
+ - utilisateur proprio banni :
+ Politique définie dans RadiusOption
+ - user à jour : VLAN_OK (réassignation de l'ipv4 au besoin)
+ - interface inconnue :
+ - register mac désactivé : Politique définie
+ dans RadiusOption
+ - register mac activé: redirection vers webauth
+ Returns:
+ tuple avec :
+ - Nom du switch (str)
+ - chambre (str)
+ - raison de la décision (str)
+ - vlan_id (int)
+ - decision (bool)
"""
# Get port from switch and port number
extra_log = ""
# Si le NAS est inconnu, on place sur le vlan defaut
if not nas_machine:
- return ('?', u'Chambre inconnue', u'Nas inconnu', VLAN_OK)
+ return ('?', u'Chambre inconnue', u'Nas inconnu', RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, True)
sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine)))
@@ -361,7 +383,13 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
# Aucune information particulière ne permet de déterminer quelle
# politique à appliquer sur ce port
if not port:
- return (sw_name, "Chambre inconnue", u'Port inconnu', VLAN_OK)
+ return (
+ sw_name,
+ "Chambre inconnue",
+ u'Port inconnu',
+ getattr(RadiusOption.get_cached_value('unknown_port_vlan'), 'vlan_id', None),
+ RadiusOption.get_cached_value('unknown_port')!= RadiusOption.REJECT
+ )
# On récupère le profil du port
port_profile = port.get_port_profile
@@ -372,46 +400,82 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
DECISION_VLAN = int(port_profile.vlan_untagged.vlan_id)
extra_log = u"Force sur vlan " + str(DECISION_VLAN)
else:
- DECISION_VLAN = VLAN_OK
+ DECISION_VLAN = RadiusOption.get_cached_value('vlan_decision_ok').vlan_id
- # Si le port est désactivé, on rejette sur le vlan de déconnexion
+ # Si le port est désactivé, on rejette la connexion
if not port.state:
- return (sw_name, port.room, u'Port desactivé', VLAN_NOK)
+ return (sw_name, port.room, u'Port desactive', None, False)
# Si radius est désactivé, on laisse passer
if port_profile.radius_type == 'NO':
return (sw_name,
"",
u"Pas d'authentification sur ce port" + extra_log,
- DECISION_VLAN)
+ DECISION_VLAN,
+ True)
- # Si le 802.1X est activé sur ce port, cela veut dire que la personne a été accept précédemment
+ # Si le 802.1X est activé sur ce port, cela veut dire que la personne a
+ # été accept précédemment
# Par conséquent, on laisse passer sur le bon vlan
- if nas_type.port_access_mode == '802.1X' and port_profile.radius_type == '802.1X':
+ if (nas_type.port_access_mode, port_profile.radius_type) == ('802.1X', '802.1X'):
room = port.room or "Chambre/local inconnu"
- return (sw_name, room, u'Acceptation authentification 802.1X', DECISION_VLAN)
+ return (
+ sw_name,
+ room,
+ u'Acceptation authentification 802.1X',
+ DECISION_VLAN,
+ True
+ )
# Sinon, cela veut dire qu'on fait de l'auth radius par mac
# Si le port est en mode strict, on vérifie que tous les users
- # rattachés à ce port sont bien à jour de cotisation. Sinon on rejette (anti squattage)
- # Il n'est pas possible de se connecter sur une prise strict sans adhérent à jour de cotis
- # dedans
+ # rattachés à ce port sont bien à jour de cotisation. Sinon on rejette
+ # (anti squattage)
+ # Il n'est pas possible de se connecter sur une prise strict sans adhérent
+ # à jour de cotis dedans
if port_profile.radius_mode == 'STRICT':
room = port.room
if not room:
- return (sw_name, "Inconnue", u'Chambre inconnue', VLAN_NOK)
+ return (
+ sw_name,
+ "Inconnue",
+ u'Chambre inconnue',
+ getattr(RadiusOption.get_cached_value('unknown_room_vlan'), 'vlan_id', None),
+ RadiusOption.get_cached_value('unknown_room')!= RadiusOption.REJECT
+ )
room_user = User.objects.filter(
Q(club__room=port.room) | Q(adherent__room=port.room)
)
if not room_user:
- return (sw_name, room, u'Chambre non cotisante', VLAN_NOK)
+ return (
+ sw_name,
+ room,
+ u'Chambre non cotisante -> Web redirect',
+ None,
+ False
+ )
for user in room_user:
- if not user.has_access():
- return (sw_name, room, u'Chambre resident desactive', VLAN_NOK)
+ if user.is_ban() or user.state != User.STATE_ACTIVE:
+ return (
+ sw_name,
+ room,
+ u'Utilisateur banni ou desactive -> Web redirect',
+ None,
+ False
+ )
+ elif not (user.is_connected() or user.is_whitelisted()):
+ return (
+ sw_name,
+ room,
+ u'Utilisateur non cotisant',
+ getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None),
+ RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT
+ )
# else: user OK, on passe à la verif MAC
- # Si on fait de l'auth par mac, on cherche l'interface via sa mac dans la bdd
+ # Si on fait de l'auth par mac, on cherche l'interface
+ # via sa mac dans la bdd
if port_profile.radius_mode == 'COMMON' or port_profile.radius_mode == 'STRICT':
# Authentification par mac
interface = (Interface.objects
@@ -421,88 +485,67 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
.first())
if not interface:
room = port.room
- # On essaye de register la mac, si l'autocapture a été activée
- # Sinon on rejette sur vlan_nok
- if not nas_type.autocapture_mac:
- return (sw_name, "", u'Machine inconnue', VLAN_NOK)
- # On ne peut autocapturer que si on connait la chambre et donc l'user correspondant
- elif not room:
- return (sw_name,
- "Inconnue",
- u'Chambre et machine inconnues',
- VLAN_NOK)
+ # On essaye de register la mac, si l'autocapture a été activée,
+ # on rejette pour faire une redirection web si possible.
+ if nas_type.autocapture_mac:
+ return (
+ sw_name,
+ room,
+ u'Machine Inconnue -> Web redirect',
+ None,
+ False
+ )
+ # Sinon on bascule sur la politique définie dans les options
+ # radius.
else:
- # Si la chambre est vide (local club, prises en libre services)
- # Impossible d'autocapturer
- if not room_user:
- room_user = User.objects.filter(
- Q(club__room=port.room) | Q(adherent__room=port.room)
- )
- if not room_user:
- return (sw_name,
- room,
- u'Machine et propriétaire de la chambre '
- 'inconnus',
- VLAN_NOK)
- # Si il y a plus d'un user dans la chambre, impossible de savoir à qui
- # Ajouter la machine
- elif room_user.count() > 1:
- return (sw_name,
- room,
- u'Machine inconnue, il y a au moins 2 users '
- 'dans la chambre/local -> ajout de mac '
- 'automatique impossible',
- VLAN_NOK)
- # Si l'adhérent de la chambre n'est pas à jour de cotis, pas d'autocapture
- elif not room_user.first().has_access():
- return (sw_name,
- room,
- u'Machine inconnue et adhérent non cotisant',
- VLAN_NOK)
- # Sinon on capture et on laisse passer sur le bon vlan
- else:
- interface, reason = (room_user
- .first()
- .autoregister_machine(
- mac_address,
- nas_type
- ))
- if interface:
- ## Si on choisi de placer les machines sur le vlan correspondant à leur type :
- if RADIUS_POLICY == 'MACHINE':
- DECISION_VLAN = interface.type.ip_type.vlan.vlan_id
- return (sw_name,
- room,
- u'Access Ok, Capture de la mac: ' + extra_log,
- DECISION_VLAN)
- else:
- return (sw_name,
- room,
- u'Erreur dans le register mac %s' % (
- reason + str(mac_address)
- ),
- VLAN_NOK)
- # L'interface a été trouvée, on vérifie qu'elle est active, sinon on reject
+ return (
+ sw_name,
+ "",
+ u'Machine inconnue',
+ getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None),
+ RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT
+ )
+
+ # L'interface a été trouvée, on vérifie qu'elle est active,
+ # sinon on reject
# Si elle n'a pas d'ipv4, on lui en met une
# Enfin on laisse passer sur le vlan pertinent
else:
room = port.room
+ if interface.machine.user.is_ban():
+ return (
+ sw_name,
+ room,
+ u'Adherent banni',
+ getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None),
+ RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT
+ )
if not interface.is_active:
- return (sw_name,
- room,
- u'Machine non active / adherent non cotisant',
- VLAN_NOK)
- ## Si on choisi de placer les machines sur le vlan correspondant à leur type :
- if RADIUS_POLICY == 'MACHINE':
+ return (
+ sw_name,
+ room,
+ u'Machine non active / adherent non cotisant',
+ getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None),
+ RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT
+ )
+ # Si on choisi de placer les machines sur le vlan
+ # correspondant à leur type :
+ if RadiusOption.get_cached_value('radius_general_policy') == 'MACHINE':
DECISION_VLAN = interface.type.ip_type.vlan.vlan_id
if not interface.ipv4:
interface.assign_ipv4()
- return (sw_name,
- room,
- u"Ok, Reassignation de l'ipv4" + extra_log,
- DECISION_VLAN)
+ return (
+ sw_name,
+ room,
+ u"Ok, Reassignation de l'ipv4" + extra_log,
+ DECISION_VLAN,
+ True
+ )
else:
- return (sw_name,
- room,
- u'Machine OK' + extra_log,
- DECISION_VLAN)
+ return (
+ sw_name,
+ room,
+ u'Machine OK' + extra_log,
+ DECISION_VLAN,
+ True
+ )
diff --git a/install_re2o.sh b/install_re2o.sh
index 6168ec08..d6b0a4ef 100755
--- a/install_re2o.sh
+++ b/install_re2o.sh
@@ -59,7 +59,7 @@ _ask_value() {
install_requirements() {
- ### Usage: install_requirements
+ ### Usage: install_requirements
#
# This function will install the required packages from APT repository
# and Pypi repository. Those packages are all required for Re2o to work
@@ -273,7 +273,7 @@ write_settings_file() {
django_secret_key="$(python -c "import random; print(''.join([random.SystemRandom().choice('abcdefghijklmnopqrstuvwxyz0123456789%=+') for i in range(50)]))")"
aes_key="$(python -c "import random; print(''.join([random.SystemRandom().choice('abcdefghijklmnopqrstuvwxyz0123456789%=+') for i in range(32)]))")"
-
+
if [ "$db_engine_type" == 1 ]; then
sed -i 's/db_engine/django.db.backends.mysql/g' "$SETTINGS_LOCAL_FILE"
else
@@ -316,6 +316,25 @@ update_django() {
echo "Collecting web frontend statics ..."
python3 manage.py collectstatic --noinput
echo "Collecting web frontend statics: Done"
+
+ echo "Generating locales ..."
+ python3 manage.py compilemessages
+ echo "Generating locales: Done"
+}
+
+
+
+copy_templates_files() {
+ ### Usage: copy_templates_files
+ #
+ # This will copy LaTeX templates in the media root.
+
+ echo "Copying LaTeX templates ..."
+ mkdir -p media/templates/
+ cp cotisations/templates/cotisations/factures.tex media/templates/default_invoice.tex
+ cp cotisations/templates/cotisations/voucher.tex media/templates/default_voucher.tex
+ chown -R www-data:www-data media/templates/
+ echo "Copying LaTeX templates: Done"
}
@@ -472,7 +491,7 @@ interactive_guide() {
sql_host="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --inputbox "$INPUTBOX" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
-
+
# Prompt to enter the remote database name
TITLE="SQL database name"
INPUTBOX="The name of the remote SQL database"
@@ -519,14 +538,14 @@ interactive_guide() {
ldap_is_local="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --menu "$MENU" \
$HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)"
-
+
# Prompt to enter the LDAP domain extension
TITLE="Domain extension"
INPUTBOX="The local domain extension to use (e.g. 'example.net'). This is used in the LDAP configuration."
extension_locale="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --inputbox "$INPUTBOX" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
-
+
# Building the DN of the LDAP from the extension
IFS='.' read -a extension_locale_array <<< $extension_locale
for i in "${extension_locale_array[@]}"
@@ -542,7 +561,7 @@ interactive_guide() {
ldap_host="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --inputbox "$INPUTBOX" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
-
+
# Prompt to choose if TLS should be activated or not for the LDAP
TITLE="TLS on LDAP"
MENU="Would you like to activate TLS for communicating with the remote LDAP ?"
@@ -579,7 +598,7 @@ interactive_guide() {
#########################
BACKTITLE="Re2o setup - configuration of the mail server"
-
+
# Prompt to enter the hostname of the mail server
TITLE="Mail server hostname"
INPUTBOX="The hostname of the mail server to use"
@@ -587,7 +606,7 @@ interactive_guide() {
--title "$TITLE" --inputbox "$TITLE" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
- # Prompt to choose the port of the mail server
+ # Prompt to choose the port of the mail server
TITLE="Mail server port"
MENU="Which port (thus which protocol) to use to contact the mail server"
OPTIONS=(25 "SMTP"
@@ -604,7 +623,7 @@ interactive_guide() {
########################
BACKTITLE="Re2o setup - configuration of the web server"
-
+
# Prompt to choose the web server
TITLE="Web server to use"
MENU="Which web server to install for accessing Re2o web frontend (automatic setup of nginx is not supported) ?"
@@ -613,14 +632,14 @@ interactive_guide() {
web_serveur="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --menu "$MENU" \
$HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)"
-
+
# Prompt to enter the requested URL for the web frontend
TITLE="Web URL"
INPUTBOX="URL for accessing the web server (e.g. re2o.example.net). Be sure that this URL is accessible and correspond to a DNS entry (if applicable)."
url_server="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --inputbox "$INPUTBOX" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
-
+
# Prompt to choose if the TLS should be setup or not for the web server
TITLE="TLS on web server"
MENU="Would you like to activate the TLS (with Let'Encrypt) on the web server ?"
@@ -675,7 +694,7 @@ interactive_guide() {
update_django
create_superuser
-
+
install_webserver "$web_serveur" "$is_tls" "$url_server"
@@ -744,9 +763,10 @@ main_function() {
echo " * {help} ---------- Display this quick usage documentation"
echo " * {setup} --------- Launch the full interactive guide to setup entirely"
echo " re2o from scratch"
- echo " * {update} -------- Collect frontend statics, install the missing APT"
+ echo " * {update} -------- Collect frontend statics, install the missing APT and copy LaTeX templates files"
echo " and pip packages and apply the migrations to the DB"
echo " * {update-django} - Apply Django migration and collect frontend statics"
+ echo " * {copy-template-files} - Copy LaTeX templates files to media/templates"
echo " * {update-packages} Install the missing APT and pip packages"
echo " * {update-settings} Interactively rewrite the settings file"
echo " * {reset-db} ------ Erase the previous local database, setup a new empty"
@@ -778,9 +798,14 @@ main_function() {
update )
install_requirements
+ copy_templates_files
update_django
;;
+ copy-templates-files )
+ copy_templates_files
+ ;;
+
update-django )
update_django
;;
@@ -796,7 +821,7 @@ main_function() {
reset-db )
if [ ! -z "$2" ]; then
db_password="$2"
- case "$3" in
+ case "$3" in
mysql )
db_engine_type=1;;
postresql )
diff --git a/logs/locale/fr/LC_MESSAGES/django.mo b/logs/locale/fr/LC_MESSAGES/django.mo
deleted file mode 100644
index 030b0cac..00000000
Binary files a/logs/locale/fr/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/logs/locale/fr/LC_MESSAGES/django.po b/logs/locale/fr/LC_MESSAGES/django.po
index 70c58073..807bda76 100644
--- a/logs/locale/fr/LC_MESSAGES/django.po
+++ b/logs/locale/fr/LC_MESSAGES/django.po
@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-08-15 20:12+0200\n"
+"POT-Creation-Date: 2019-01-08 23:16+0100\n"
"PO-Revision-Date: 2018-06-23 16:01+0200\n"
"Last-Translator: Laouen Fernet \n"
"Language-Team: \n"
@@ -57,7 +57,7 @@ msgstr "Commentaire"
#: templates/logs/aff_stats_logs.html:58 templates/logs/aff_summary.html:62
#: templates/logs/aff_summary.html:85 templates/logs/aff_summary.html:104
-#: templates/logs/aff_summary.html:123 templates/logs/aff_summary.html:142
+#: templates/logs/aff_summary.html:128 templates/logs/aff_summary.html:147
msgid "Cancel"
msgstr "Annuler"
@@ -113,15 +113,19 @@ msgstr "%(username)s a mis à jour"
#: templates/logs/aff_summary.html:113
#, python-format
-msgid "%(username)s has sold %(number)sx %(name)s to"
-msgstr "%(username)s a vendu %(number)sx %(name)s à"
+msgid "%(username)s has sold %(number)sx %(name)s"
+msgstr "%(username)s a vendu %(number)sx %(name)s"
#: templates/logs/aff_summary.html:116
+msgid " to"
+msgstr " à"
+
+#: templates/logs/aff_summary.html:119
#, python-format
msgid "+%(duration)s months"
msgstr "+%(duration)s mois"
-#: templates/logs/aff_summary.html:132
+#: templates/logs/aff_summary.html:137
#, python-format
msgid "%(username)s has edited an interface of"
msgstr "%(username)s a modifié une interface de"
@@ -149,7 +153,7 @@ msgstr "Confirmer"
msgid "Statistics"
msgstr "Statistiques"
-#: templates/logs/index.html:32 templates/logs/stats_logs.html:32 views.py:403
+#: templates/logs/index.html:32 templates/logs/stats_logs.html:32 views.py:414
msgid "Actions performed"
msgstr "Actions effectuées"
@@ -173,7 +177,7 @@ msgstr "Base de données"
msgid "Wiring actions"
msgstr "Actions de câblage"
-#: templates/logs/sidebar.html:53 views.py:325
+#: templates/logs/sidebar.html:53 views.py:336
msgid "Users"
msgstr "Utilisateurs"
@@ -189,150 +193,154 @@ msgstr "Statistiques sur la base de données"
msgid "Statistics about users"
msgstr "Statistiques sur les utilisateurs"
-#: views.py:191
+#: views.py:194
msgid "Nonexistent revision."
msgstr "Révision inexistante."
-#: views.py:194
+#: views.py:197
msgid "The action was deleted."
msgstr "L'action a été supprimée."
-#: views.py:227
+#: views.py:230
msgid "Category"
msgstr "Catégorie"
-#: views.py:228
+#: views.py:231
msgid "Number of users (members and clubs)"
msgstr "Nombre d'utilisateurs (adhérents et clubs)"
-#: views.py:229
+#: views.py:232
msgid "Number of members"
msgstr "Nombre d'adhérents"
-#: views.py:230
+#: views.py:233
msgid "Number of clubs"
msgstr "Nombre de clubs"
-#: views.py:234
+#: views.py:237
msgid "Activated users"
msgstr "Utilisateurs activés"
-#: views.py:242
+#: views.py:245
msgid "Disabled users"
msgstr "Utilisateurs désactivés"
-#: views.py:250
+#: views.py:253
msgid "Archived users"
msgstr "Utilisateurs archivés"
-#: views.py:258
+#: views.py:261
+msgid "Not yet active users"
+msgstr "Utilisateurs pas encore actifs"
+
+#: views.py:269
msgid "Contributing members"
msgstr "Adhérents cotisants"
-#: views.py:264
+#: views.py:275
msgid "Users benefiting from a connection"
msgstr "Utilisateurs bénéficiant d'une connexion"
-#: views.py:270
+#: views.py:281
msgid "Banned users"
msgstr "Utilisateurs bannis"
-#: views.py:276
+#: views.py:287
msgid "Users benefiting from a free connection"
msgstr "Utilisateurs bénéficiant d'une connexion gratuite"
-#: views.py:282
+#: views.py:293
msgid "Active interfaces (with access to the network)"
msgstr "Interfaces actives (ayant accès au réseau)"
-#: views.py:292
+#: views.py:303
msgid "Active interfaces assigned IPv4"
msgstr "Interfaces actives assignées IPv4"
-#: views.py:305
+#: views.py:316
msgid "IP range"
msgstr "Plage d'IP"
-#: views.py:306
+#: views.py:317
msgid "VLAN"
msgstr "VLAN"
-#: views.py:307
+#: views.py:318
msgid "Total number of IP addresses"
msgstr "Nombre total d'adresses IP"
-#: views.py:308
+#: views.py:319
msgid "Number of assigned IP addresses"
msgstr "Nombre d'adresses IP non assignées"
-#: views.py:309
+#: views.py:320
msgid "Number of IP address assigned to an activated machine"
msgstr "Nombre d'adresses IP assignées à une machine activée"
-#: views.py:310
+#: views.py:321
msgid "Number of nonassigned IP addresses"
msgstr "Nombre d'adresses IP non assignées"
-#: views.py:337
+#: views.py:348
msgid "Subscriptions"
msgstr "Cotisations"
-#: views.py:359 views.py:420
+#: views.py:370 views.py:431
msgid "Machines"
msgstr "Machines"
-#: views.py:386
+#: views.py:397
msgid "Topology"
msgstr "Topologie"
-#: views.py:405
+#: views.py:416
msgid "Number of actions"
msgstr "Nombre d'actions"
-#: views.py:419 views.py:437 views.py:442 views.py:447 views.py:462
+#: views.py:430 views.py:448 views.py:453 views.py:458 views.py:473
msgid "User"
msgstr "Utilisateur"
-#: views.py:423
+#: views.py:434
msgid "Invoice"
msgstr "Facture"
-#: views.py:426
+#: views.py:437
msgid "Ban"
msgstr "Bannissement"
-#: views.py:429
+#: views.py:440
msgid "Whitelist"
msgstr "Accès gracieux"
-#: views.py:432
+#: views.py:443
msgid "Rights"
msgstr "Droits"
-#: views.py:436
+#: views.py:447
msgid "School"
msgstr "Établissement"
-#: views.py:441
+#: views.py:452
msgid "Payment method"
msgstr "Moyen de paiement"
-#: views.py:446
+#: views.py:457
msgid "Bank"
msgstr "Banque"
-#: views.py:463
+#: views.py:474
msgid "Action"
msgstr "Action"
-#: views.py:494
+#: views.py:505
msgid "No model found."
msgstr "Aucun modèle trouvé."
-#: views.py:500
+#: views.py:511
msgid "Nonexistent entry."
msgstr "Entrée inexistante."
-#: views.py:507
+#: views.py:518
msgid "You don't have the right to access this menu."
msgstr "Vous n'avez pas le droit d'accéder à ce menu."
diff --git a/logs/templates/logs/aff_stats_logs.html b/logs/templates/logs/aff_stats_logs.html
index 1ca79df9..44a937f9 100644
--- a/logs/templates/logs/aff_stats_logs.html
+++ b/logs/templates/logs/aff_stats_logs.html
@@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% if revisions_list.paginator %}
-{% include "pagination.html" with list=revisions_list %}
+ {% include 'pagination.html' with list=revisions_list %}
{% endif %}
{% load logs_extra %}
@@ -36,9 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Edited object" %}
{% trans "Object type" %}
{% trans "Edited by" as tr_edited_by %}
-
{% include "buttons/sort.html" with prefix='logs' col='author' text=tr_edited_by %}
+
{% include 'buttons/sort.html' with prefix='logs' col='author' text=tr_edited_by %}
{% trans "Date of editing" as tr_date_of_editing %}
-
{% include "buttons/sort.html" with prefix='logs' col='date' text=tr_date_of_editing %}
+
{% include 'buttons/sort.html' with prefix='logs' col='date' text=tr_date_of_editing %}
{% trans "Comment" %}
@@ -65,6 +65,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if revisions_list.paginator %}
-{% include "pagination.html" with list=revisions_list %}
+ {% include 'pagination.html' with list=revisions_list %}
{% endif %}
diff --git a/logs/templates/logs/aff_summary.html b/logs/templates/logs/aff_summary.html
index 366e07e7..3c43e2ac 100644
--- a/logs/templates/logs/aff_summary.html
+++ b/logs/templates/logs/aff_summary.html
@@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% if versions_list.paginator %}
-{% include "pagination.html" with list=versions_list %}
+ {% include 'pagination.html' with list=versions_list %}
{% endif %}
{% load logs_extra %}
@@ -35,7 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Date" as tr_date %}
-
{% include "buttons/sort.html" with prefix='sum' col='date' text=tr_date %}
+
{% include 'buttons/sort.html' with prefix='sum' col='date' text=tr_date %}
{% trans "Editing" %}
@@ -154,6 +154,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if versions_list.paginator %}
-{% include "pagination.html" with list=versions_list %}
+ {% include 'pagination.html' with list=versions_list %}
{% endif %}
diff --git a/logs/templates/logs/delete.html b/logs/templates/logs/delete.html
index 6ad11195..a8f6b52f 100644
--- a/logs/templates/logs/delete.html
+++ b/logs/templates/logs/delete.html
@@ -1,4 +1,4 @@
-{% extends "logs/sidebar.html" %}
+{% extends 'logs/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
diff --git a/logs/templates/logs/index.html b/logs/templates/logs/index.html
index dde47c7d..3bd61b40 100644
--- a/logs/templates/logs/index.html
+++ b/logs/templates/logs/index.html
@@ -1,4 +1,4 @@
-{% extends "logs/sidebar.html" %}
+{% extends 'logs/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
{% trans "Actions performed" %}
- {% include "logs/aff_summary.html" with versions_list=versions_list %}
+ {% include 'logs/aff_summary.html' with versions_list=versions_list %}
diff --git a/logs/templates/logs/sidebar.html b/logs/templates/logs/sidebar.html
index 87011cfc..e997abd5 100644
--- a/logs/templates/logs/sidebar.html
+++ b/logs/templates/logs/sidebar.html
@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends 'base.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -28,27 +28,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block sidebar %}
{% can_view_app logs %}
-
-
+
+
{% trans "Summary" %}
-
-
+
+
{% trans "Events" %}
-
-
+
+
{% trans "General" %}
-
+
{% trans "Database" %}
-
+
{% trans "Wiring actions" %}
-
+
{% trans "Users" %}
diff --git a/logs/templates/logs/stats_general.html b/logs/templates/logs/stats_general.html
index 07e3ec26..96d5612c 100644
--- a/logs/templates/logs/stats_general.html
+++ b/logs/templates/logs/stats_general.html
@@ -1,4 +1,4 @@
-{% extends "logs/sidebar.html" %}
+{% extends 'logs/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
{% trans "General statistics" %}
- {% include "logs/aff_stats_general.html" with stats_list=stats_list %}
+ {% include 'logs/aff_stats_general.html' with stats_list=stats_list %}
diff --git a/logs/templates/logs/stats_logs.html b/logs/templates/logs/stats_logs.html
index 4f547cc3..df9708b1 100644
--- a/logs/templates/logs/stats_logs.html
+++ b/logs/templates/logs/stats_logs.html
@@ -1,4 +1,4 @@
-{% extends "logs/sidebar.html" %}
+{% extends 'logs/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
{% trans "Actions performed" %}
- {% include "logs/aff_stats_logs.html" with revisions_list=revisions_list %}
+ {% include 'logs/aff_stats_logs.html' with revisions_list=revisions_list %}
diff --git a/logs/templates/logs/stats_models.html b/logs/templates/logs/stats_models.html
index 9b912da2..ddc66c15 100644
--- a/logs/templates/logs/stats_models.html
+++ b/logs/templates/logs/stats_models.html
@@ -1,4 +1,4 @@
-{% extends "logs/sidebar.html" %}
+{% extends 'logs/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
{% trans "Database statistics" %}
- {% include "logs/aff_stats_models.html" with stats_list=stats_list %}
+ {% include 'logs/aff_stats_models.html' with stats_list=stats_list %}
diff --git a/logs/templates/logs/stats_users.html b/logs/templates/logs/stats_users.html
index 8cc645ab..d55d1e52 100644
--- a/logs/templates/logs/stats_users.html
+++ b/logs/templates/logs/stats_users.html
@@ -1,4 +1,4 @@
-{% extends "logs/sidebar.html" %}
+{% extends 'logs/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
{% trans "Statistics about users" %}
- {% include "logs/aff_stats_users.html" with stats_list=stats_list %}
+ {% include 'logs/aff_stats_users.html' with stats_list=stats_list %}
diff --git a/logs/views.py b/logs/views.py
index a9fe5418..a54edd56 100644
--- a/logs/views.py
+++ b/logs/views.py
@@ -102,15 +102,18 @@ from re2o.utils import (
all_baned,
all_has_access,
all_adherent,
+ all_active_assigned_interfaces_count,
+ all_active_interfaces_count,
+)
+from re2o.base import (
re2o_paginator,
+ SortTable
)
from re2o.acl import (
can_view_all,
can_view_app,
can_edit_history,
)
-from re2o.utils import all_active_assigned_interfaces_count
-from re2o.utils import all_active_interfaces_count, SortTable
@login_required
@@ -254,6 +257,14 @@ def stats_general(request):
.count()),
Club.objects.filter(state=Club.STATE_ARCHIVE).count()
],
+ 'not_active_users': [
+ _("Not yet active users"),
+ User.objects.filter(state=User.STATE_NOT_YET_ACTIVE).count(),
+ (Adherent.objects
+ .filter(state=Adherent.STATE_NOT_YET_ACTIVE)
+ .count()),
+ Club.objects.filter(state=Club.STATE_NOT_YET_ACTIVE).count()
+ ],
'adherent_users': [
_("Contributing members"),
_all_adherent.count(),
diff --git a/machines/acl.py b/machines/acl.py
index 45cb6ec2..53f70c27 100644
--- a/machines/acl.py
+++ b/machines/acl.py
@@ -41,4 +41,3 @@ def can_view(user):
can = user.has_module_perms('machines')
return can, None if can else _("You don't have the right to view this"
" application.")
-
diff --git a/machines/admin.py b/machines/admin.py
index af721ff9..bafebb80 100644
--- a/machines/admin.py
+++ b/machines/admin.py
@@ -29,7 +29,6 @@ from __future__ import unicode_literals
from django.contrib import admin
from reversion.admin import VersionAdmin
-from .models import IpType, Machine, MachineType, Domain, IpList, Interface
from .models import (
Extension,
SOA,
@@ -47,6 +46,7 @@ from .models import (
Ipv6List,
OuverturePortList,
)
+from .models import IpType, Machine, MachineType, Domain, IpList, Interface
class MachineAdmin(VersionAdmin):
@@ -98,6 +98,7 @@ class TxtAdmin(VersionAdmin):
""" Admin view of a TXT object """
pass
+
class DNameAdmin(VersionAdmin):
""" Admin view of a DName object """
pass
@@ -147,12 +148,12 @@ class ServiceAdmin(VersionAdmin):
""" Admin view of a ServiceAdmin object """
list_display = ('service_type', 'min_time_regen', 'regular_time_regen')
+
class RoleAdmin(VersionAdmin):
""" Admin view of a RoleAdmin object """
pass
-
admin.site.register(Machine, MachineAdmin)
admin.site.register(MachineType, MachineTypeAdmin)
admin.site.register(IpType, IpTypeAdmin)
diff --git a/machines/forms.py b/machines/forms.py
index 4af060d3..94b9293a 100644
--- a/machines/forms.py
+++ b/machines/forms.py
@@ -35,13 +35,12 @@ Formulaires d'ajout, edition et suppressions de :
from __future__ import unicode_literals
-from django.forms import ModelForm, Form
from django import forms
+from django.forms import ModelForm, Form
from django.utils.translation import ugettext_lazy as _
from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
-
from .models import (
Domain,
Machine,
@@ -68,6 +67,7 @@ from .models import (
class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Formulaire d'édition d'une machine"""
+
class Meta:
model = Machine
fields = '__all__'
@@ -80,12 +80,14 @@ class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
class NewMachineForm(EditMachineForm):
"""Creation d'une machine, ne renseigne que le nom"""
+
class Meta(EditMachineForm.Meta):
fields = ['name']
class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Edition d'une interface. Edition complète"""
+
class Meta:
model = Interface
fields = ['machine', 'type', 'ipv4', 'mac_address', 'details']
@@ -116,7 +118,7 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
interface=self.instance
)
if "machine" in self.fields:
- self.fields['machine'].queryset = Machine.objects.all()\
+ self.fields['machine'].queryset = Machine.objects.all() \
.select_related('user')
can_use_all_machinetype, _reason = MachineType.can_use_all(user)
if not can_use_all_machinetype:
@@ -128,12 +130,14 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
class AddInterfaceForm(EditInterfaceForm):
"""Ajout d'une interface à une machine. En fonction des droits,
affiche ou non l'ensemble des ip disponibles"""
+
class Meta(EditInterfaceForm.Meta):
fields = ['type', 'ipv4', 'mac_address', 'details']
class AliasForm(FormRevMixin, ModelForm):
"""Ajout d'un alias (et edition), CNAME, contenant nom et extension"""
+
class Meta:
model = Domain
fields = ['name', 'extension']
@@ -151,6 +155,7 @@ class AliasForm(FormRevMixin, ModelForm):
class DomainForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un enregistrement de nom, relié à interface"""
+
class Meta:
model = Domain
fields = ['name']
@@ -183,6 +188,7 @@ class DelAliasForm(FormRevMixin, Form):
class MachineTypeForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un machinetype, relié à un iptype"""
+
class Meta:
model = MachineType
fields = ['type', 'ip_type']
@@ -214,6 +220,7 @@ class DelMachineTypeForm(FormRevMixin, Form):
class IpTypeForm(FormRevMixin, ModelForm):
"""Formulaire d'ajout d'un iptype. Pas d'edition de l'ip de start et de
stop après creation"""
+
class Meta:
model = IpType
fields = '__all__'
@@ -227,6 +234,7 @@ class IpTypeForm(FormRevMixin, ModelForm):
class EditIpTypeForm(IpTypeForm):
"""Edition d'un iptype. Pas d'edition du rangev4 possible, car il faudrait
synchroniser les objets iplist"""
+
class Meta(IpTypeForm.Meta):
fields = ['extension', 'type', 'need_infra', 'domaine_ip_network', 'domaine_ip_netmask',
'prefix_v6', 'prefix_v6_length',
@@ -253,6 +261,7 @@ class DelIpTypeForm(FormRevMixin, Form):
class ExtensionForm(FormRevMixin, ModelForm):
"""Formulaire d'ajout et edition d'une extension"""
+
class Meta:
model = Extension
fields = '__all__'
@@ -264,6 +273,7 @@ class ExtensionForm(FormRevMixin, ModelForm):
self.fields['origin'].label = _("A record origin")
self.fields['origin_v6'].label = _("AAAA record origin")
self.fields['soa'].label = _("SOA record to use")
+ self.fields['dnssec'].label = _("Sign with DNSSEC")
class DelExtensionForm(FormRevMixin, Form):
@@ -285,6 +295,7 @@ class DelExtensionForm(FormRevMixin, Form):
class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
"""Gestion des ipv6 d'une machine"""
+
class Meta:
model = Ipv6List
fields = ['ipv6', 'slaac_ip']
@@ -296,6 +307,7 @@ class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
class SOAForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un SOA"""
+
class Meta:
model = SOA
fields = '__all__'
@@ -324,6 +336,7 @@ class DelSOAForm(FormRevMixin, Form):
class MxForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un MX"""
+
class Meta:
model = Mx
fields = ['zone', 'priority', 'name']
@@ -357,6 +370,7 @@ class NsForm(FormRevMixin, ModelForm):
"""Ajout d'un NS pour une zone
On exclue les CNAME dans les objets domain (interdit par la rfc)
donc on prend uniquemet """
+
class Meta:
model = Ns
fields = ['zone', 'ns']
@@ -388,6 +402,7 @@ class DelNsForm(FormRevMixin, Form):
class TxtForm(FormRevMixin, ModelForm):
"""Ajout d'un txt pour une zone"""
+
class Meta:
model = Txt
fields = '__all__'
@@ -416,6 +431,7 @@ class DelTxtForm(FormRevMixin, Form):
class DNameForm(FormRevMixin, ModelForm):
"""Add a DNAME entry for a zone"""
+
class Meta:
model = DName
fields = '__all__'
@@ -444,6 +460,7 @@ class DelDNameForm(FormRevMixin, Form):
class SrvForm(FormRevMixin, ModelForm):
"""Ajout d'un srv pour une zone"""
+
class Meta:
model = Srv
fields = '__all__'
@@ -473,6 +490,7 @@ class DelSrvForm(FormRevMixin, Form):
class NasForm(FormRevMixin, ModelForm):
"""Ajout d'un type de nas (machine d'authentification,
swicths, bornes...)"""
+
class Meta:
model = Nas
fields = '__all__'
@@ -501,6 +519,7 @@ class DelNasForm(FormRevMixin, Form):
class RoleForm(FormRevMixin, ModelForm):
"""Add and edit role."""
+
class Meta:
model = Role
fields = '__all__'
@@ -509,9 +528,9 @@ class RoleForm(FormRevMixin, ModelForm):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(RoleForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['servers'].queryset = (Interface.objects.all()
- .select_related(
- 'domain__extension'
- ))
+ .select_related(
+ 'domain__extension'
+ ))
class DelRoleForm(FormRevMixin, Form):
@@ -533,6 +552,7 @@ class DelRoleForm(FormRevMixin, Form):
class ServiceForm(FormRevMixin, ModelForm):
"""Ajout et edition d'une classe de service : dns, dhcp, etc"""
+
class Meta:
model = Service
fields = '__all__'
@@ -541,9 +561,9 @@ class ServiceForm(FormRevMixin, ModelForm):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['servers'].queryset = (Interface.objects.all()
- .select_related(
- 'domain__extension'
- ))
+ .select_related(
+ 'domain__extension'
+ ))
def save(self, commit=True):
# TODO : None of the parents of ServiceForm use the commit
@@ -574,15 +594,27 @@ class DelServiceForm(FormRevMixin, Form):
class VlanForm(FormRevMixin, ModelForm):
"""Ajout d'un vlan : id, nom"""
+
class Meta:
model = Vlan
- fields = '__all__'
+ fields = ['vlan_id', 'name', 'comment']
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs)
+class EditOptionVlanForm(FormRevMixin, ModelForm):
+ """Ajout d'un vlan : id, nom"""
+ class Meta:
+ model = Vlan
+ fields = ['dhcp_snooping', 'dhcpv6_snooping', 'arp_protect', 'igmp', 'mld']
+
+ def __init__(self, *args, **kwargs):
+ prefix = kwargs.pop('prefix', self.Meta.model.__name__)
+ super(EditOptionVlanForm, self).__init__(*args, prefix=prefix, **kwargs)
+
+
class DelVlanForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs vlans"""
vlan = forms.ModelMultipleChoiceField(
@@ -603,6 +635,7 @@ class DelVlanForm(FormRevMixin, Form):
class EditOuverturePortConfigForm(FormRevMixin, ModelForm):
"""Edition de la liste des profils d'ouverture de ports
pour l'interface"""
+
class Meta:
model = Interface
fields = ['port_lists']
@@ -619,6 +652,7 @@ class EditOuverturePortConfigForm(FormRevMixin, ModelForm):
class EditOuverturePortListForm(FormRevMixin, ModelForm):
"""Edition de la liste des ports et profils d'ouverture
des ports"""
+
class Meta:
model = OuverturePortList
fields = '__all__'
@@ -631,9 +665,10 @@ class EditOuverturePortListForm(FormRevMixin, ModelForm):
**kwargs
)
-
+
class SshFpForm(FormRevMixin, ModelForm):
"""Edits a SSHFP record."""
+
class Meta:
model = SshFp
exclude = ('machine',)
@@ -645,4 +680,3 @@ class SshFpForm(FormRevMixin, ModelForm):
prefix=prefix,
**kwargs
)
-
diff --git a/machines/locale/fr/LC_MESSAGES/django.mo b/machines/locale/fr/LC_MESSAGES/django.mo
deleted file mode 100644
index c9696d92..00000000
Binary files a/machines/locale/fr/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/machines/locale/fr/LC_MESSAGES/django.po b/machines/locale/fr/LC_MESSAGES/django.po
index 50ab03a8..bd36fb61 100644
--- a/machines/locale/fr/LC_MESSAGES/django.po
+++ b/machines/locale/fr/LC_MESSAGES/django.po
@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-08-15 18:10+0200\n"
+"POT-Creation-Date: 2019-01-12 16:43+0100\n"
"PO-Revision-Date: 2018-06-23 16:35+0200\n"
"Last-Translator: Laouen Fernet \n"
"Language-Team: \n"
@@ -38,220 +38,232 @@ msgstr "Vous n'avez pas le droit de voir cette application."
msgid "Machine name"
msgstr "Nom de la machine"
-#: forms.py:97 templates/machines/aff_machines.html:46
+#: forms.py:99 templates/machines/aff_machines.html:46
msgid "MAC address"
msgstr "Adresse MAC"
-#: forms.py:98 templates/machines/aff_machinetype.html:32
+#: forms.py:100 templates/machines/aff_machinetype.html:32
#: templates/machines/machine.html:112
msgid "Machine type"
msgstr "Type de machine"
-#: forms.py:99
+#: forms.py:101
msgid "Select a machine type"
msgstr "Sélectionnez un type de machine"
-#: forms.py:101
+#: forms.py:103
msgid "Automatic IPv4 assignment"
msgstr "Assignation automatique IPv4"
-#: forms.py:172
+#: forms.py:177
msgid "Current aliases"
msgstr "Alias actuels"
-#: forms.py:193
+#: forms.py:199
msgid "Machine type to add"
msgstr "Type de machine à ajouter"
-#: forms.py:194
+#: forms.py:200
msgid "Related IP type"
msgstr "Type d'IP relié"
-#: forms.py:201
+#: forms.py:207
msgid "Current machine types"
msgstr "Types de machines actuels"
-#: forms.py:224
+#: forms.py:231
msgid "IP type to add"
msgstr "Type d'IP à ajouter"
-#: forms.py:241
+#: forms.py:249
msgid "Current IP types"
msgstr "Types d'IP actuels"
-#: forms.py:263
+#: forms.py:272
msgid "Extension to add"
msgstr "Extension à ajouter"
-#: forms.py:264 templates/machines/aff_extension.html:37
+#: forms.py:273 templates/machines/aff_extension.html:37
msgid "A record origin"
msgstr "Enregistrement A origin"
-#: forms.py:265 templates/machines/aff_extension.html:39
+#: forms.py:274 templates/machines/aff_extension.html:39
msgid "AAAA record origin"
msgstr "Enregistrement AAAA origin"
-#: forms.py:266
+#: forms.py:275
msgid "SOA record to use"
msgstr "Enregistrement SOA à utiliser"
-#: forms.py:273
+#: forms.py:276
+msgid "Sign with DNSSEC"
+msgstr "Signer avec DNSSEC"
+
+#: forms.py:283
msgid "Current extensions"
msgstr "Extensions actuelles"
-#: forms.py:312
+#: forms.py:324
msgid "Current SOA records"
msgstr "Enregistrements SOA actuels"
-#: forms.py:343
+#: forms.py:356
msgid "Current MX records"
msgstr "Enregistrements MX actuels"
-#: forms.py:376
+#: forms.py:390
msgid "Current NS records"
msgstr "Enregistrements NS actuels"
-#: forms.py:404
+#: forms.py:419
msgid "Current TXT records"
msgstr "Enregistrements TXT actuels"
-#: forms.py:432
+#: forms.py:448
msgid "Current DNAME records"
msgstr "Enregistrements DNAME actuels"
-#: forms.py:460
+#: forms.py:477
msgid "Current SRV records"
msgstr "Enregistrements SRV actuels"
-#: forms.py:489
+#: forms.py:507
msgid "Current NAS devices"
msgstr "Dispositifs NAS actuels"
-#: forms.py:521
+#: forms.py:540
msgid "Current roles"
msgstr "Rôles actuels"
-#: forms.py:562
+#: forms.py:582
msgid "Current services"
msgstr "Services actuels"
-#: forms.py:590
+#: forms.py:622
msgid "Current VLANs"
msgstr "VLANs actuels"
-#: models.py:63
+#: models.py:61
msgid "Optional"
msgstr "Optionnel"
-#: models.py:71
+#: models.py:69
msgid "Can view a machine object"
msgstr "Peut voir un objet machine"
-#: models.py:73
+#: models.py:71
msgid "Can change the user of a machine"
msgstr "Peut changer l'utilisateur d'une machine"
-#: models.py:75
+#: models.py:73
msgid "machine"
msgstr "machine"
-#: models.py:76
+#: models.py:74
msgid "machines"
msgstr "machines"
-#: models.py:109
+#: models.py:107
msgid "You don't have the right to change the machine's user."
msgstr "Vous n'avez pas le droit de changer l'utilisateur de la machine."
-#: models.py:118
+#: models.py:116
msgid "You don't have the right to view all the machines."
msgstr "Vous n'avez pas le droit de voir toutes les machines."
-#: models.py:132
+#: models.py:130
msgid "Nonexistent user."
msgstr "Utilisateur inexistant."
-#: models.py:140
+#: models.py:138
msgid "You don't have the right to add a machine."
msgstr "Vous n'avez pas le droit d'ajouter une machine."
-#: models.py:142
+#: models.py:140
msgid "You don't have the right to add a machine to another user."
msgstr "Vous n'avez pas le droit d'ajouter une machine à un autre utilisateur."
-#: models.py:145 models.py:1152
+#: models.py:143 models.py:1182
#, python-format
msgid ""
"You reached the maximum number of interfaces that you are allowed to create "
"yourself (%s)."
msgstr ""
"Vous avez atteint le nombre maximal d'interfaces que vous pouvez créer vous-"
-"mêmes (%s)."
+"même (%s)."
-#: models.py:164 models.py:1177 models.py:1194 models.py:1296 models.py:1313
+#: models.py:162 models.py:1207 models.py:1224 models.py:1326 models.py:1343
msgid "You don't have the right to edit a machine of another user."
msgstr ""
"Vous n'avez pas le droit de modifier une machine d'un autre utilisateur."
-#: models.py:182
+#: models.py:180
msgid "You don't have the right to delete a machine of another user."
msgstr ""
"Vous n'avez pas le droit de supprimer une machine d'une autre utilisateur."
-#: models.py:194
+#: models.py:192
msgid "You don't have the right to view other machines than yours."
msgstr "Vous n'avez pas le droit de voir d'autres machines que les vôtres."
-#: models.py:241
+#: models.py:204 templates/machines/aff_machines.html:53
+msgid "No name"
+msgstr "Sans nom"
+
+#: models.py:254
msgid "Can view a machine type object"
msgstr "Peut voir un objet type de machine"
-#: models.py:242
+#: models.py:255
msgid "Can use all machine types"
msgstr "Peut utiliser tous les types de machine"
-#: models.py:244
+#: models.py:257
msgid "machine type"
msgstr "type de machine"
-#: models.py:245
+#: models.py:258
msgid "machine types"
msgstr "types de machine"
-#: models.py:263
+#: models.py:276
msgid "You don't have the right to use all machine types."
msgstr "Vous n'avez pas le droit d'utiliser tous les types de machine."
-#: models.py:282
+#: models.py:295
msgid "Network containing the domain's IPv4 range (optional)"
msgstr "Réseau contenant la plage IPv4 du domaine (optionnel)"
-#: models.py:290
+#: models.py:303
msgid "Netmask for the domain's IPv4 range"
msgstr "Masque de sous-réseau pour la plage IPv4 du domaine"
-#: models.py:294
+#: models.py:307
msgid "Enable reverse DNS for IPv4"
msgstr "Activer DNS inverse pour IPv4"
-#: models.py:310
+#: models.py:323
msgid "Enable reverse DNS for IPv6"
-msgstr "Activer DNS inverser pour IPv6"
+msgstr "Activer DNS inverse pour IPv6"
-#: models.py:326
+#: models.py:339
msgid "Can view an IP type object"
msgstr "Peut voir un objet type d'IP"
-#: models.py:327
+#: models.py:340
msgid "Can use all IP types"
msgstr "Peut utiliser tous les types d'IP"
-#: models.py:329 templates/machines/aff_iptype.html:35
+#: models.py:342 templates/machines/aff_iptype.html:35
#: templates/machines/machine.html:108
msgid "IP type"
msgstr "type d'IP"
-#: models.py:433
+#: models.py:343
+msgid "IP types"
+msgstr "types d'IP"
+
+#: models.py:446
msgid ""
"One or several IP addresses from the range are affected, impossible to "
"delete the range."
@@ -259,57 +271,69 @@ msgstr ""
"Une ou plusieurs adresses IP de la plage sont affectées, impossible de "
"supprimer la plage."
-#: models.py:475
+#: models.py:488
msgid "Range end must be after range start..."
msgstr "La fin de la plage doit être après le début..."
-#: models.py:478
+#: models.py:491
msgid "The range is too large, you can't create a larger one than a /16."
msgstr ""
"La plage est trop grande, vous ne pouvez pas en créer une plus grande "
"qu'un /16."
-#: models.py:483
+#: models.py:496
msgid "The specified range is not disjoint from existing ranges."
msgstr "La plage renseignée n'est pas disjointe des plages existantes."
-#: models.py:491
+#: models.py:504
msgid ""
"If you specify a domain network or netmask, it must contain the domain's IP "
"range."
msgstr ""
-"Si vous renseignez un réseau ou masque de sous-réseau, il doit contenir"
-" la plage IP du domaine."
+"Si vous renseignez un réseau ou masque de sous-réseau, il doit contenir la "
+"plage IP du domaine."
-#: models.py:521
+#: models.py:537
+msgid "v4 multicast management"
+msgstr "gestion de multidiffusion v4"
+
+#: models.py:541
+msgid "v6 multicast management"
+msgstr "gestion de multidiffusion v6"
+
+#: models.py:546
msgid "Can view a VLAN object"
msgstr "Peut voir un objet VLAN"
-#: models.py:523 templates/machines/machine.html:160
+#: models.py:548 templates/machines/machine.html:160
msgid "VLAN"
msgstr "VLAN"
-#: models.py:524 templates/machines/sidebar.html:57
+#: models.py:549 templates/machines/sidebar.html:57
msgid "VLANs"
msgstr "VLANs"
-#: models.py:560
+#: models.py:562
+msgid "MAC-address"
+msgstr "MAC-address"
+
+#: models.py:585
msgid "Can view a NAS device object"
msgstr "Peut voir un objet dispositif NAS"
-#: models.py:562 templates/machines/machine.html:164
+#: models.py:587 templates/machines/machine.html:164
msgid "NAS device"
msgstr "dispositif NAS"
-#: models.py:563 templates/machines/sidebar.html:63
+#: models.py:588 templates/machines/sidebar.html:63
msgid "NAS devices"
msgstr "dispositifs NAS"
-#: models.py:577
+#: models.py:602
msgid "Contact email address for the zone"
msgstr "Adresse mail de contact pour la zone"
-#: models.py:581
+#: models.py:606
msgid ""
"Seconds before the secondary DNS have to ask the primary DNS serial to "
"detect a modification"
@@ -317,7 +341,7 @@ msgstr ""
"Secondes avant que le DNS secondaire demande au DNS primaire le serial pour "
"détecter une modification"
-#: models.py:586
+#: models.py:611
msgid ""
"Seconds before the secondary DNS ask the serial again in case of a primary "
"DNS timeout"
@@ -325,7 +349,7 @@ msgstr ""
"Secondes avant que le DNS secondaire demande le serial de nouveau dans le "
"cas d'un délai d'attente du DNS primaire"
-#: models.py:591
+#: models.py:616
msgid ""
"Seconds before the secondary DNS stop answering requests in case of primary "
"DNS timeout"
@@ -333,108 +357,112 @@ msgstr ""
"Secondes avant que le DNS secondaire arrête de répondre aux requêtes dans le "
"cas d'un délai d'attente du DNS primaire"
-#: models.py:596 models.py:846
+#: models.py:621 models.py:878
msgid "Time to Live"
msgstr "Temps de vie"
-#: models.py:601
+#: models.py:626
msgid "Can view an SOA record object"
msgstr "Peut voir un objet enregistrement SOA"
-#: models.py:603 templates/machines/aff_extension.html:36
+#: models.py:628 templates/machines/aff_extension.html:36
#: templates/machines/machine.html:120
msgid "SOA record"
msgstr "enregistrement SOA"
-#: models.py:604
+#: models.py:629
msgid "SOA records"
msgstr "enregistrements SOA"
-#: models.py:643
+#: models.py:668
msgid "SOA to edit"
msgstr "SOA à modifier"
-#: models.py:654
+#: models.py:679
msgid "Zone name, must begin with a dot (.example.org)"
msgstr "Nom de zone, doit commencer par un point (.example.org)"
-#: models.py:662
+#: models.py:687
msgid "A record associated with the zone"
msgstr "Enregistrement A associé à la zone"
-#: models.py:668
+#: models.py:693
msgid "AAAA record associated with the zone"
msgstr "Enregristrement AAAA associé avec la zone"
-#: models.py:677
+#: models.py:701
+msgid "Should the zone be signed with DNSSEC"
+msgstr "La zone doit-elle être signée avec DNSSEC"
+
+#: models.py:706
msgid "Can view an extension object"
msgstr "Peut voir un objet extension"
-#: models.py:678
+#: models.py:707
msgid "Can use all extensions"
msgstr "Peut utiliser toutes les extensions"
-#: models.py:680
+#: models.py:709
msgid "DNS extension"
msgstr "extension DNS"
-#: models.py:681
+#: models.py:710
msgid "DNS extensions"
msgstr "extensions DNS"
-#: models.py:732
+#: models.py:764
msgid "An extension must begin with a dot."
msgstr "Une extension doit commencer par un point."
-#: models.py:746
+#: models.py:778
msgid "Can view an MX record object"
msgstr "Peut voir un objet enregistrement MX"
-#: models.py:748 templates/machines/machine.html:124
+#: models.py:780 templates/machines/machine.html:124
msgid "MX record"
msgstr "enregistrement MX"
-#: models.py:749
+#: models.py:781
msgid "MX records"
msgstr "enregistrements MX"
-#: models.py:771
+#: models.py:803
msgid "Can view an NS record object"
msgstr "Peut voir un objet enregistrement NS"
-#: models.py:773 templates/machines/machine.html:128
+#: models.py:805 templates/machines/machine.html:128
msgid "NS record"
msgstr "enregistrement NS"
-#: models.py:774
+#: models.py:806
msgid "NS records"
msgstr "enregistrements NS"
-#: models.py:793
+#: models.py:825
msgid "Can view a TXT record object"
msgstr "Peut voir un objet enregistrement TXT"
-#: models.py:795 templates/machines/machine.html:132
+#: models.py:827 templates/machines/machine.html:132
msgid "TXT record"
msgstr "enregistrement TXT"
-#: models.py:796
+#: models.py:828
msgid "TXT records"
msgstr "enregistrements TXT"
-#: models.py:815
+#: models.py:847
msgid "Can view a DNAME record object"
msgstr "Peut voir un objet enregistrement DNAME"
-#: models.py:817 templates/machines/machine.html:136
+#: models.py:849 templates/machines/machine.html:136
msgid "DNAME record"
msgstr "enregistrement DNAME"
-#: models.py:818
+#: models.py:850
msgid "DNAME records"
msgstr "enregistrements DNAME"
-#: models.py:851
+#: models.py:883
msgid ""
"Priority of the target server (positive integer value, the lower it is, the "
"more the server will be used if available)"
@@ -442,7 +470,7 @@ msgstr ""
"Priorité du serveur cible (entier positif, plus il est bas, plus le serveur "
"sera utilisé si disponible)"
-#: models.py:858
+#: models.py:890
msgid ""
"Relative weight for records with the same priority (integer value between 0 "
"and 65535)"
@@ -450,128 +478,137 @@ msgstr ""
"Poids relatif des enregistrements avec la même priorité (entier entre 0 et "
"65535)"
-#: models.py:863
+#: models.py:895
msgid "TCP/UDP port"
msgstr "Port TCP/UDP"
-#: models.py:868
+#: models.py:900
msgid "Target server"
msgstr "Serveur cible"
-#: models.py:873
+#: models.py:905
msgid "Can view an SRV record object"
msgstr "Peut voir un objet enregistrement SRV"
-#: models.py:875 templates/machines/machine.html:140
+#: models.py:907 templates/machines/machine.html:140
msgid "SRV record"
msgstr "enregistrement SRV"
-#: models.py:876
+#: models.py:908
msgid "SRV records"
msgstr "enregistrements SRV"
-#: models.py:940
+#: models.py:937 templates/machines/aff_sshfp.html:31
+msgid "SSH public key"
+msgstr "Clé publique SSH"
+
+#: models.py:945 templates/machines/aff_sshfp.html:33
+#: templates/machines/aff_vlan.html:35
+msgid "Comment"
+msgstr "Commentaire"
+
+#: models.py:972
msgid "Can view an SSHFP record object"
msgstr "Peut voir un objet enregistrement SSHFP"
-#: models.py:942 templates/machines/machine.html:144
+#: models.py:974 templates/machines/machine.html:144
msgid "SSHFP record"
msgstr "enregistrement SSHFP"
-#: models.py:943
+#: models.py:975
msgid "SSHFP records"
msgstr "enregistrements SSHFP"
-#: models.py:981
+#: models.py:1012
msgid "Can view an interface object"
msgstr "Peut voir un objet interface"
-#: models.py:983
+#: models.py:1014
msgid "Can change the owner of an interface"
msgstr "Peut changer l'utilisateur d'une interface"
-#: models.py:985
+#: models.py:1016
msgid "interface"
msgstr "interface"
-#: models.py:986
+#: models.py:1017
msgid "interfaces"
msgstr "interfaces"
-#: models.py:1080
+#: models.py:1111
msgid "The given MAC address is invalid."
msgstr "L'adresse MAC indiquée est invalide."
-#: models.py:1093
+#: models.py:1124
msgid "The selected IP type is invalid."
msgstr "Le type d'IP sélectionné est invalide."
-#: models.py:1106
+#: models.py:1136
msgid "There is no IP address available in the slash."
msgstr "Il n'y a pas d'adresse IP disponible dans le slash."
-#: models.py:1124
+#: models.py:1154
msgid "The IPv4 address and the machine type don't match."
msgstr "L'adresse IPv4 et le type de machine ne correspondent pas."
-#: models.py:1138
+#: models.py:1168
msgid "Nonexistent machine."
msgstr "Machine inexistante."
-#: models.py:1142
+#: models.py:1172
msgid "You can't add a machine."
msgstr "Vous ne pouvez pas ajouter une machine."
-#: models.py:1148
+#: models.py:1178
msgid ""
"You don't have the right to add an interface to a machine of another user."
msgstr ""
"Vous n'avez pas le droit d'ajouter une interface à une machine d'un autre "
"utilisateur."
-#: models.py:1162
+#: models.py:1192
msgid "Permission required to edit the machine."
msgstr "Permission requise pour modifier la machine."
-#: models.py:1206 models.py:1325 models.py:1532
+#: models.py:1236 models.py:1355 models.py:1565
msgid "You don't have the right to view machines other than yours."
msgstr "Vous n'avez pas le droit de voir d'autres machines que les vôtres."
-#: models.py:1252
+#: models.py:1282
msgid "Can view an IPv6 addresses list object"
msgstr "Peut voir un objet list d'adresses IPv6"
-#: models.py:1253
+#: models.py:1283
msgid "Can change the SLAAC value of an IPv6 addresses list"
msgstr "Peut modifier la valeur SLAAC d'une liste d'adresses IPv6"
-#: models.py:1256
+#: models.py:1286
msgid "IPv6 addresses list"
msgstr "Liste d'adresses IPv6"
-#: models.py:1257
+#: models.py:1287
msgid "IPv6 addresses lists"
msgstr "Listes d'adresses IPv6"
-#: models.py:1269 models.py:1480
+#: models.py:1299 models.py:1513
msgid "Nonexistent interface."
msgstr "Interface inexistante."
-#: models.py:1272 models.py:1487
+#: models.py:1302 models.py:1520
msgid "You don't have the right to add an alias to a machine of another user."
msgstr ""
"Vous n'avez pas le droit d'ajouter un alias à une machine d'un autre "
"utilisateur."
-#: models.py:1280
+#: models.py:1310
msgid "Permission required to change the SLAAC value of an IPv6 address"
msgstr "Permission requise pour changer la valeur SLAAC d'une adresse IPv6."
-#: models.py:1352
+#: models.py:1382
msgid "A SLAAC IP address is already registered."
msgstr "Une adresse IP SLAAC est déjà enregistrée."
-#: models.py:1357
+#: models.py:1390
msgid ""
"The v6 prefix is incorrect and doesn't match the type associated with the "
"machine."
@@ -579,207 +616,207 @@ msgstr ""
"Le préfixe v6 est incorrect et ne correspond pas au type associé à la "
"machine."
-#: models.py:1383
+#: models.py:1416
msgid "Mandatory and unique, must not contain dots."
msgstr "Obligatoire et unique, ne doit pas contenir de points."
-#: models.py:1397
+#: models.py:1430
msgid "Can view a domain object"
msgstr "Peut voir un objet domaine"
-#: models.py:1399
+#: models.py:1432
msgid "domain"
msgstr "domaine"
-#: models.py:1400
+#: models.py:1433
msgid "domains"
msgstr "domaines"
-#: models.py:1422
+#: models.py:1455
msgid "You can't create a both A and CNAME record."
msgstr "Vous ne pouvez pas créer un enregistrement à la fois A et CNAME."
-#: models.py:1425
+#: models.py:1458
msgid "You can't create a CNAME record pointing to itself."
msgstr "Vous ne pouvez pas créer un enregistrement CNAME vers lui-même."
-#: models.py:1433
+#: models.py:1466
#, python-format
msgid "The domain name %s is too long (over 63 characters)."
msgstr "Le nom de domaine %s est trop long (plus de 63 caractères)."
-#: models.py:1436
+#: models.py:1469
#, python-format
msgid "The domain name %s contains forbidden characters."
msgstr "Le nom de domaine %s contient des caractères interdits."
-#: models.py:1454
+#: models.py:1487
msgid "Invalid extension."
msgstr "Extension invalide."
-#: models.py:1495
+#: models.py:1528
#, python-format
msgid ""
"You reached the maximum number of alias that you are allowed to create "
"yourself (%s). "
msgstr ""
-"Vous avez atteint le nombre maximal d'alias que vous pouvez créer vous-mêmes "
+"Vous avez atteint le nombre maximal d'alias que vous pouvez créer vous-même "
"(%s)."
-#: models.py:1508
+#: models.py:1541
msgid "You don't have the right to edit an alias of a machine of another user."
msgstr ""
"Vous n'avez pas le droit de modifier un alias d'une machine d'un autre "
"utilisateur."
-#: models.py:1520
+#: models.py:1553
msgid ""
"You don't have the right to delete an alias of a machine of another user."
msgstr ""
"Vous n'avez pas le droit de supprimer un alias d'une machine d'un autre "
"utilisateur."
-#: models.py:1548
+#: models.py:1581
msgid "Can view an IPv4 addresses list object"
msgstr "Peut voir un object liste d'adresses IPv4"
-#: models.py:1550
+#: models.py:1583
msgid "IPv4 addresses list"
msgstr "Liste d'adresses IPv4"
-#: models.py:1551
+#: models.py:1584
msgid "IPv4 addresses lists"
msgstr "Listes d'adresses IPv4"
-#: models.py:1562
+#: models.py:1595
msgid "The IPv4 address and the range of the IP type don't match."
msgstr "L'adresse IPv4 et la plage du type d'IP ne correspondent pas."
-#: models.py:1580
+#: models.py:1613
msgid "DHCP server"
msgstr "Serveur DHCP"
-#: models.py:1581
+#: models.py:1614
msgid "Switches configuration server"
msgstr "Serveur de configuration des commutateurs réseau"
-#: models.py:1582
+#: models.py:1615
msgid "Recursive DNS server"
msgstr "Serveur DNS récursif"
-#: models.py:1583
+#: models.py:1616
msgid "NTP server"
msgstr "Serveur NTP"
-#: models.py:1584
+#: models.py:1617
msgid "RADIUS server"
msgstr "Serveur RADIUS"
-#: models.py:1585
+#: models.py:1618
msgid "Log server"
msgstr "Serveur log"
-#: models.py:1586
+#: models.py:1619
msgid "LDAP master server"
msgstr "Serveur LDAP maître"
-#: models.py:1587
+#: models.py:1620
msgid "LDAP backup server"
msgstr "Serveur LDAP de secours"
-#: models.py:1588
+#: models.py:1621
msgid "SMTP server"
msgstr "Serveur SMTP"
-#: models.py:1589
+#: models.py:1622
msgid "postgreSQL server"
msgstr "Serveur postgreSQL"
-#: models.py:1590
+#: models.py:1623
msgid "mySQL server"
msgstr "Serveur mySQL"
-#: models.py:1591
+#: models.py:1624
msgid "SQL client"
msgstr "Client SQL"
-#: models.py:1592
+#: models.py:1625
msgid "Gateway"
msgstr "Passerelle"
-#: models.py:1606
+#: models.py:1639
msgid "Can view a role object"
msgstr "Peut voir un objet rôle"
-#: models.py:1608
+#: models.py:1641
msgid "server role"
msgstr "rôle de serveur"
-#: models.py:1609
+#: models.py:1642
msgid "server roles"
msgstr "rôles de serveur"
-#: models.py:1650
+#: models.py:1676
msgid "Minimal time before regeneration of the service."
msgstr "Temps minimal avant régénération du service."
-#: models.py:1654
+#: models.py:1680
msgid "Maximal time before regeneration of the service."
msgstr "Temps maximal avant régénération du service."
-#: models.py:1660
+#: models.py:1686
msgid "Can view a service object"
msgstr "Peut voir un objet service"
-#: models.py:1662
+#: models.py:1688
msgid "service to generate (DHCP, DNS, ...)"
msgstr "service à générer (DHCP, DNS, ...)"
-#: models.py:1663
+#: models.py:1689
msgid "services to generate (DHCP, DNS, ...)"
msgstr "services à générer (DHCP, DNS, ...)"
-#: models.py:1709
+#: models.py:1735
msgid "Can view a service server link object"
msgstr "Peut voir un objet lien service serveur"
-#: models.py:1711
+#: models.py:1737
msgid "link between service and server"
msgstr "lien entre service et serveur"
-#: models.py:1712
+#: models.py:1738
msgid "links between service and server"
msgstr "liens entre service et serveur"
-#: models.py:1754
+#: models.py:1780
msgid "Name of the ports configuration"
msgstr "Nom de la configuration de ports"
-#: models.py:1760
+#: models.py:1786
msgid "Can view a ports opening list object"
msgstr "Peut voir un objet liste d'ouverture de ports"
-#: models.py:1763
+#: models.py:1789
msgid "ports opening list"
msgstr "liste d'ouverture de ports"
-#: models.py:1764
+#: models.py:1790
msgid "ports opening lists"
msgstr "listes d'ouverture de ports"
-#: models.py:1773
+#: models.py:1799
msgid "You don't have the right to delete a ports opening list."
msgstr "Vous n'avez pas le droit de supprimer une liste d'ouverture de ports."
-#: models.py:1776
+#: models.py:1802
msgid "This ports opening list is used."
msgstr "Cette liste d'ouverture de ports est utilisée."
-#: models.py:1849
+#: models.py:1875
msgid "ports opening"
msgstr "ouverture de ports"
-#: models.py:1850
+#: models.py:1876
msgid "ports openings"
msgstr "ouvertures de ports"
@@ -807,6 +844,10 @@ msgstr "Extension"
msgid "'infra' right required"
msgstr "droit 'infra' requis"
+#: templates/machines/aff_extension.html:41
+msgid "DNSSEC"
+msgstr "DNSSEC"
+
#: templates/machines/aff_iptype.html:38
msgid "IPv4 range"
msgstr "Plage IPv4"
@@ -851,43 +892,39 @@ msgstr "Adresse IP"
msgid "Actions"
msgstr "Actions"
-#: templates/machines/aff_machines.html:53
-msgid "No name"
-msgstr "Sans nom"
-
#: templates/machines/aff_machines.html:54
msgid "View the profile"
msgstr "Voir le profil"
-#: templates/machines/aff_machines.html:62 views.py:375
+#: templates/machines/aff_machines.html:62 views.py:374
msgid "Create an interface"
msgstr "Créer une interface"
-#: templates/machines/aff_machines.html:77
+#: templates/machines/aff_machines.html:79
msgid "Display the aliases"
msgstr "Afficher les alias"
-#: templates/machines/aff_machines.html:95
+#: templates/machines/aff_machines.html:99
msgid "Display the IPv6 address"
msgstr "Afficher les adresses IPv6"
-#: templates/machines/aff_machines.html:110
+#: templates/machines/aff_machines.html:116
msgid " Edit"
msgstr " Modifier"
-#: templates/machines/aff_machines.html:118
+#: templates/machines/aff_machines.html:124
msgid " Manage the aliases"
msgstr " Gérer les alias"
-#: templates/machines/aff_machines.html:126
+#: templates/machines/aff_machines.html:132
msgid " Manage the IPv6 addresses"
msgstr " Gérer les adresses IPv6"
-#: templates/machines/aff_machines.html:134
+#: templates/machines/aff_machines.html:140
msgid " Manage the SSH fingerprints"
msgstr " Gérer les empreintes SSH"
-#: templates/machines/aff_machines.html:142
+#: templates/machines/aff_machines.html:148
msgid " Manage the ports configuration"
msgstr " Gérer les configuration de ports"
@@ -906,7 +943,7 @@ msgstr "Priorité"
#: templates/machines/aff_nas.html:33 templates/machines/aff_soa.html:32
#: templates/machines/aff_vlan.html:34
-#: templates/machines/index_portlist.html:18
+#: templates/machines/index_portlist.html:20
msgid "Name"
msgstr "Nom"
@@ -1019,18 +1056,10 @@ msgstr "Port"
msgid "Target"
msgstr "Cible"
-#: templates/machines/aff_sshfp.html:31
-msgid "SSH public key"
-msgstr "Clé publique SSH"
-
#: templates/machines/aff_sshfp.html:32
msgid "Algorithm used"
msgstr "Algorithme utilisé"
-#: templates/machines/aff_sshfp.html:33 templates/machines/aff_vlan.html:35
-msgid "Comment"
-msgstr "Commentaire"
-
#: templates/machines/aff_vlan.html:33
msgid "ID"
msgstr "ID"
@@ -1040,8 +1069,8 @@ msgid "IP ranges"
msgstr "Plages d'IP"
#: templates/machines/delete.html:29
-msgid "Creation and editing of machines"
-msgstr "Création et modification de machines"
+msgid "Deletion of machines"
+msgstr "Suppression de machines"
#: templates/machines/delete.html:35
#, python-format
@@ -1058,16 +1087,16 @@ msgstr "Confirmer"
#: templates/machines/edit_portlist.html:29 templates/machines/index.html:29
#: templates/machines/index.html:32 templates/machines/index_alias.html:29
-#: templates/machines/index_extension.html:31
-#: templates/machines/index_iptype.html:31
+#: templates/machines/index_extension.html:30
+#: templates/machines/index_iptype.html:30
#: templates/machines/index_ipv6.html:30
#: templates/machines/index_machinetype.html:31
#: templates/machines/index_nas.html:31
#: templates/machines/index_portlist.html:8
-#: templates/machines/index_portlist.html:23
+#: templates/machines/index_portlist.html:25
#: templates/machines/index_role.html:30
#: templates/machines/index_service.html:30
-#: templates/machines/index_sshfp.html:28 templates/machines/index_vlan.html:31
+#: templates/machines/index_sshfp.html:28 templates/machines/index_vlan.html:30
#: templates/machines/machine.html:31 templates/machines/sidebar.html:33
msgid "Machines"
msgstr "Machines"
@@ -1084,99 +1113,99 @@ msgstr "Créer ou modifier"
msgid "List of the aliases of the interface"
msgstr "Liste des alias de l'interface"
-#: templates/machines/index_alias.html:33
+#: templates/machines/index_alias.html:34
msgid " Add an alias"
msgstr " Ajouter un alias"
-#: templates/machines/index_alias.html:34
+#: templates/machines/index_alias.html:36
msgid " Delete one or several aliases"
msgstr " Supprimer un ou plusieurs alias"
-#: templates/machines/index_extension.html:34
+#: templates/machines/index_extension.html:33
msgid "List of extensions"
msgstr "Liste des extensions"
-#: templates/machines/index_extension.html:36
+#: templates/machines/index_extension.html:37
msgid " Add an extension"
msgstr " Ajouter une extension"
-#: templates/machines/index_extension.html:38
+#: templates/machines/index_extension.html:40
msgid " Delete one or several extensions"
msgstr " Supprimer une ou plusieurs extensions"
-#: templates/machines/index_extension.html:41
+#: templates/machines/index_extension.html:44
msgid "List of SOA records"
msgstr "Liste des enregistrements SOA"
-#: templates/machines/index_extension.html:43
+#: templates/machines/index_extension.html:47
msgid " Add an SOA record"
msgstr " Ajouter un enregistrement SOA"
-#: templates/machines/index_extension.html:45
+#: templates/machines/index_extension.html:51
msgid " Delete one or several SOA records"
msgstr " Supprimer un ou plusieurs enregistrements SOA"
-#: templates/machines/index_extension.html:48
+#: templates/machines/index_extension.html:55
msgid "List of MX records"
msgstr "Liste des enregistrements MX"
-#: templates/machines/index_extension.html:50
+#: templates/machines/index_extension.html:58
msgid " Add an MX record"
msgstr " Ajouter un enregistrement MX"
-#: templates/machines/index_extension.html:52
+#: templates/machines/index_extension.html:62
msgid " Delete one or several MX records"
msgstr " Supprimer un ou plusieurs enregistrements MX"
-#: templates/machines/index_extension.html:55
+#: templates/machines/index_extension.html:66
msgid "List of NS records"
msgstr "Liste des enregistrements NS"
-#: templates/machines/index_extension.html:57
+#: templates/machines/index_extension.html:69
msgid " Add an NS record"
msgstr " Ajouter un enregistrement NS"
-#: templates/machines/index_extension.html:59
+#: templates/machines/index_extension.html:73
msgid " Delete one or several NS records"
msgstr " Supprimer un ou plusieurs enregistrements NS"
-#: templates/machines/index_extension.html:62
+#: templates/machines/index_extension.html:77
msgid "List of TXT records"
msgstr "Liste des enregistrements TXT"
-#: templates/machines/index_extension.html:64
+#: templates/machines/index_extension.html:80
msgid " Add a TXT record"
msgstr " Ajouter un enregistrement TXT"
-#: templates/machines/index_extension.html:66
+#: templates/machines/index_extension.html:84
msgid " Delete one or several TXT records"
msgstr " Supprimer un ou plusieurs enregistrements TXT"
-#: templates/machines/index_extension.html:69
+#: templates/machines/index_extension.html:88
msgid "List of DNAME records"
msgstr "Liste des enregistrements DNAME"
-#: templates/machines/index_extension.html:72
+#: templates/machines/index_extension.html:91
msgid " Add a DNAME record"
msgstr " Ajouter un enregistrement DNAME"
-#: templates/machines/index_extension.html:76
+#: templates/machines/index_extension.html:95
msgid " Delete one or several DNAME records"
msgstr " Supprimer un ou plusieurs enregistrements DNAME"
-#: templates/machines/index_extension.html:80
+#: templates/machines/index_extension.html:99
msgid "List of SRV records"
msgstr "Liste des enregistrements SRV"
-#: templates/machines/index_extension.html:82
+#: templates/machines/index_extension.html:102
msgid " Add an SRV record"
msgstr " Ajouter un enregistrement SRV"
-#: templates/machines/index_extension.html:84
+#: templates/machines/index_extension.html:106
msgid " Delete one or several SRV records"
msgstr " Supprimer un ou plusieurs enregistrements SRV"
-#: templates/machines/index_iptype.html:34
+#: templates/machines/index_iptype.html:33
msgid "List of IP types"
msgstr "Liste des types d'IP"
@@ -1184,7 +1213,7 @@ msgstr "Liste des types d'IP"
msgid " Add an IP type"
msgstr " Ajouter un type d'IP"
-#: templates/machines/index_iptype.html:38
+#: templates/machines/index_iptype.html:40
msgid " Delete one or several IP types"
msgstr " Supprimer un ou plusieurs types d'IP"
@@ -1192,7 +1221,7 @@ msgstr " Supprimer un ou plusieurs types d'IP"
msgid "List of the IPv6 addresses of the interface"
msgstr "Liste des adresses IPv6 de l'interface"
-#: templates/machines/index_ipv6.html:35
+#: templates/machines/index_ipv6.html:36
msgid " Add an IPv6 address"
msgstr " Ajouter une adresse IPv6"
@@ -1200,11 +1229,11 @@ msgstr " Ajouter une adresse IPv6"
msgid "List of machine types"
msgstr "Liste des types de machine"
-#: templates/machines/index_machinetype.html:36
+#: templates/machines/index_machinetype.html:37
msgid " Add a machine type"
msgstr " Ajouter un type de machine"
-#: templates/machines/index_machinetype.html:38
+#: templates/machines/index_machinetype.html:41
msgid " Delete one or several machine types"
msgstr " Supprimer un ou plusieurs types de machine"
@@ -1223,11 +1252,11 @@ msgstr ""
"type de machine à assigner aux machines en fonction du type de dispositif "
"NAS."
-#: templates/machines/index_nas.html:37
+#: templates/machines/index_nas.html:38
msgid " Add a NAS device type"
msgstr " Ajouter un type de dispositif NAS"
-#: templates/machines/index_nas.html:39
+#: templates/machines/index_nas.html:42
msgid " Delete one or several NAS device types"
msgstr " Supprimer un ou plusieurs types de dispositif NAS"
@@ -1235,23 +1264,23 @@ msgstr " Supprimer un ou plusieurs types de dispositif NAS"
msgid "List of ports configurations"
msgstr "Liste des configurations de ports"
-#: templates/machines/index_portlist.html:13
+#: templates/machines/index_portlist.html:14
msgid " Add a configuration"
msgstr " Ajouter une configuration"
-#: templates/machines/index_portlist.html:19
+#: templates/machines/index_portlist.html:21
msgid "TCP (input)"
msgstr "TCP (entrée)"
-#: templates/machines/index_portlist.html:20
+#: templates/machines/index_portlist.html:22
msgid "TCP (output)"
msgstr "TCP (sortie)"
-#: templates/machines/index_portlist.html:21
+#: templates/machines/index_portlist.html:23
msgid "UDP (input)"
msgstr "UDP (entrée)"
-#: templates/machines/index_portlist.html:22
+#: templates/machines/index_portlist.html:24
msgid "UDP (output)"
msgstr "UDP (sortie)"
@@ -1259,11 +1288,11 @@ msgstr "UDP (sortie)"
msgid "List of roles"
msgstr "Liste des rôles"
-#: templates/machines/index_role.html:35
+#: templates/machines/index_role.html:36
msgid " Add a role"
msgstr " Ajouter un rôle"
-#: templates/machines/index_role.html:37
+#: templates/machines/index_role.html:39
msgid " Delete one or several roles"
msgstr " Supprimer un ou plusieurs rôles"
@@ -1271,15 +1300,15 @@ msgstr " Supprimer un ou plusieurs rôles"
msgid "List of services"
msgstr "Liste des services"
-#: templates/machines/index_service.html:35
+#: templates/machines/index_service.html:36
msgid " Add a service"
msgstr " Ajouter un service"
-#: templates/machines/index_service.html:37
+#: templates/machines/index_service.html:39
msgid " Delete one or several services"
msgstr " Supprimer un ou plusieurs services"
-#: templates/machines/index_service.html:39
+#: templates/machines/index_service.html:42
msgid "States of servers"
msgstr "États des serveurs"
@@ -1291,7 +1320,7 @@ msgstr "Empreintes SSH"
msgid " Add an SSH fingerprint"
msgstr " Ajouter une empreinte SSH"
-#: templates/machines/index_vlan.html:34
+#: templates/machines/index_vlan.html:33
msgid "List of VLANs"
msgstr "Liste des VLANs"
@@ -1299,7 +1328,7 @@ msgstr "Liste des VLANs"
msgid " Add a VLAN"
msgstr " Ajouter un VLAN"
-#: templates/machines/index_vlan.html:38
+#: templates/machines/index_vlan.html:39
msgid " Delete one or several VLANs"
msgstr " Supprimer un ou plusieurs VLANs"
@@ -1343,90 +1372,90 @@ msgstr "Rôles de serveur"
msgid "Ports openings"
msgstr "Ouvertures de ports"
-#: views.py:156
-msgid "Select a machine type first.},"
-msgstr "Sélectionnez un type de machine d'abord.},"
+#: views.py:155
+msgid "Select a machine type first."
+msgstr "Sélectionnez un type de machine d'abord."
-#: views.py:258
+#: views.py:257
msgid "The machine was created."
msgstr "La machine a été créée."
-#: views.py:270
+#: views.py:269
msgid "Create a machine"
msgstr "Créer une machine"
-#: views.py:310
+#: views.py:309
msgid "The machine was edited."
msgstr "La machine a été modifiée."
-#: views.py:322 views.py:446 views.py:512 views.py:568 views.py:630
-#: views.py:691 views.py:749 views.py:806 views.py:863 views.py:919
+#: views.py:321 views.py:445 views.py:511 views.py:567 views.py:629
+#: views.py:690 views.py:748 views.py:805 views.py:862 views.py:919
#: views.py:977 views.py:1034 views.py:1106 views.py:1169 views.py:1226
#: views.py:1292 views.py:1349
msgid "Edit"
msgstr "Modifier"
-#: views.py:335
+#: views.py:334
msgid "The machine was deleted."
msgstr "La machine a été supprimée."
-#: views.py:364
+#: views.py:363
msgid "The interface was created."
msgstr "L'interface a été créée."
-#: views.py:391
+#: views.py:390
msgid "The interface was deleted."
msgstr "L'interface a été supprimée."
-#: views.py:416
+#: views.py:415
msgid "The IPv6 addresses list was created."
msgstr "La liste d'adresses IPv6 a été créée."
-#: views.py:422
+#: views.py:421
msgid "Create an IPv6 addresses list"
msgstr "Créer une liste d'adresses IPv6"
-#: views.py:440
+#: views.py:439
msgid "The IPv6 addresses list was edited."
msgstr "La liste d'adresses IPv6 a été modifiée."
-#: views.py:459
+#: views.py:458
msgid "The IPv6 addresses list was deleted."
msgstr "La liste d'adresses IPv6 a été supprimée."
-#: views.py:483
+#: views.py:482
msgid "The SSHFP record was created."
msgstr "L'enregistrement SSHFP a été créé."
-#: views.py:489
+#: views.py:488
msgid "Create a SSHFP record"
msgstr "Créer un enregistrement SSHFP"
-#: views.py:506
+#: views.py:505
msgid "The SSHFP record was edited."
msgstr "L'enregistrement SSHFP a été modifié."
-#: views.py:525
+#: views.py:524
msgid "The SSHFP record was deleted."
msgstr "L'enregistrement SSHFP a été supprimé."
-#: views.py:546
+#: views.py:545
msgid "The IP type was created."
msgstr "Le type d'IP a été créé."
-#: views.py:549
+#: views.py:548
msgid "Create an IP type"
msgstr "Créer un type d'IP"
-#: views.py:565
+#: views.py:564
msgid "The IP type was edited."
msgstr "Le type d'IP a été modifié."
-#: views.py:584
+#: views.py:583
msgid "The IP type was deleted."
msgstr "Le type d'IP a été supprimé."
-#: views.py:588
+#: views.py:587
#, python-format
msgid ""
"The IP type %s is assigned to at least one machine, you can't delete it."
@@ -1434,29 +1463,29 @@ msgstr ""
"Le type d'IP %s est assigné à au moins une machine, vous ne pouvez pas le "
"supprimer."
-#: views.py:593 views.py:655 views.py:716 views.py:773 views.py:830
-#: views.py:887 views.py:944 views.py:1001 views.py:1058 views.py:1136
+#: views.py:592 views.py:654 views.py:715 views.py:772 views.py:829
+#: views.py:886 views.py:944 views.py:1001 views.py:1058 views.py:1136
#: views.py:1193 views.py:1250 views.py:1316 views.py:1373
msgid "Delete"
msgstr "Supprimer"
-#: views.py:606
+#: views.py:605
msgid "The machine type was created."
msgstr "Le type de machine a été créé."
-#: views.py:609
+#: views.py:608
msgid "Create a machine type"
msgstr "Créer un type de machine"
-#: views.py:627
+#: views.py:626
msgid "The machine type was edited."
msgstr "Le type de machine a été modifié."
-#: views.py:646
+#: views.py:645
msgid "The machine type was deleted."
msgstr "Le type de machine a été supprimé."
-#: views.py:650
+#: views.py:649
#, python-format
msgid ""
"The machine type %s is assigned to at least one machine, you can't delete it."
@@ -1464,23 +1493,23 @@ msgstr ""
"Le type de machine %s est assigné à au moins un machine, vous ne pouvez pas "
"le supprimer."
-#: views.py:668
+#: views.py:667
msgid "The extension was created."
msgstr "L'extension a été créée."
-#: views.py:671
+#: views.py:670
msgid "Create an extension"
msgstr "Créer une extension"
-#: views.py:688
+#: views.py:687
msgid "The extension was edited."
msgstr "L'extension a été modifiée."
-#: views.py:707
+#: views.py:706
msgid "The extension was deleted."
msgstr "L'extension a été supprimée."
-#: views.py:711
+#: views.py:710
#, python-format
msgid ""
"The extension %s is assigned to at least one machine type, you can't delete "
@@ -1489,65 +1518,65 @@ msgstr ""
"L'extension %s est assignée à au moins un type de machine, vous ne pouvez "
"pas le supprimer."
-#: views.py:729
+#: views.py:728
msgid "The SOA record was created."
msgstr "L'enregistrement SOA a été créé."
-#: views.py:732
+#: views.py:731
msgid "Create an SOA record"
msgstr "Créer un enregistrement SOA"
-#: views.py:746
+#: views.py:745
msgid "The SOA record was edited."
msgstr "L'enregistrement SOA a été modifié."
-#: views.py:765
+#: views.py:764
msgid "The SOA record was deleted."
msgstr "L'enregistrement SOA a été supprimé."
-#: views.py:769
+#: views.py:768
#, python-format
msgid "Error: the SOA record %s can't be deleted."
msgstr "Erreur : l'enregistrement SOA %s ne peut pas être supprimé."
-#: views.py:786
+#: views.py:785
msgid "The MX record was created."
msgstr "L'enregistrement MX a été créé."
-#: views.py:789
+#: views.py:788
msgid "Create an MX record"
msgstr "Créer un enregistrement MX"
-#: views.py:803
+#: views.py:802
msgid "The MX record was edited."
msgstr "L'enregistrement MX a été modifié."
-#: views.py:822
+#: views.py:821
msgid "The MX record was deleted."
msgstr "L'enregistrement MX a été supprimé."
-#: views.py:826
+#: views.py:825
#, python-format
msgid "Error: the MX record %s can't be deleted."
msgstr "Erreur : l'enregistrement MX %s ne peut pas être supprimé."
-#: views.py:843
+#: views.py:842
msgid "The NS record was created."
msgstr "L'enregistrement NS a été créé."
-#: views.py:846
+#: views.py:845
msgid "Create an NS record"
msgstr "Créer un enregistrement NS"
-#: views.py:860
+#: views.py:859
msgid "The NS record was edited."
msgstr "L'enregistrement NS a été modifié."
-#: views.py:879
+#: views.py:878
msgid "The NS record was deleted."
msgstr "L'enregistrement NS a été supprimé."
-#: views.py:883
+#: views.py:882
#, python-format
msgid "Error: the NS record %s can't be deleted."
msgstr "Erreur : l'enregistrement NS %s ne peut pas être supprimé."
diff --git a/machines/migrations/0095_auto_20180919_2225.py b/machines/migrations/0095_auto_20180919_2225.py
new file mode 100644
index 00000000..66c082ff
--- /dev/null
+++ b/machines/migrations/0095_auto_20180919_2225.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-09-19 20:25
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0094_auto_20180815_1918'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='vlan',
+ name='arp_protect',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AddField(
+ model_name='vlan',
+ name='dhcp_snooping',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AddField(
+ model_name='vlan',
+ name='dhcpv6_snooping',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AddField(
+ model_name='vlan',
+ name='igmp',
+ field=models.BooleanField(default=False, help_text='Gestion multicast v4'),
+ ),
+ migrations.AddField(
+ model_name='vlan',
+ name='mld',
+ field=models.BooleanField(default=False, help_text='Gestion multicast v6'),
+ ),
+ ]
diff --git a/machines/migrations/0096_auto_20181013_1417.py b/machines/migrations/0096_auto_20181013_1417.py
new file mode 100644
index 00000000..745fb523
--- /dev/null
+++ b/machines/migrations/0096_auto_20181013_1417.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-10-13 12:17
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0095_auto_20180919_2225'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='machine',
+ name='user',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
+ ),
+ ]
diff --git a/machines/migrations/0097_extension_dnssec.py b/machines/migrations/0097_extension_dnssec.py
new file mode 100644
index 00000000..48e41f77
--- /dev/null
+++ b/machines/migrations/0097_extension_dnssec.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2018-12-24 14:00
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0096_auto_20181013_1417'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='extension',
+ name='dnssec',
+ field=models.BooleanField(default=False, help_text='Should the zone be signed with DNSSEC'),
+ ),
+ ]
diff --git a/machines/migrations/0098_auto_20190102_1745.py b/machines/migrations/0098_auto_20190102_1745.py
new file mode 100644
index 00000000..e886e8a1
--- /dev/null
+++ b/machines/migrations/0098_auto_20190102_1745.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2019-01-02 23:45
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0097_extension_dnssec'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='role',
+ name='specific_role',
+ field=models.CharField(blank=True, choices=[('dhcp-server', 'DHCP server'), ('switch-conf-server', 'Switches configuration server'), ('dns-recursif-server', 'Recursive DNS server'), ('dns-recursive-server', 'Recursive DNS server'), ('ntp-server', 'NTP server'), ('radius-server', 'RADIUS server'), ('log-server', 'Log server'), ('ldap-master-server', 'LDAP master server'), ('ldap-backup-server', 'LDAP backup server'), ('smtp-server', 'SMTP server'), ('postgresql-server', 'postgreSQL server'), ('mysql-server', 'mySQL server'), ('sql-client', 'SQL client'), ('gateway', 'Gateway')], max_length=32, null=True),
+ ),
+ ]
diff --git a/machines/migrations/0099_role_recursive_dns.py b/machines/migrations/0099_role_recursive_dns.py
new file mode 100644
index 00000000..c1ce3965
--- /dev/null
+++ b/machines/migrations/0099_role_recursive_dns.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2019-01-02 23:45
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+def migrate(apps, schema_editor):
+ Role = apps.get_model('machines', 'Role')
+
+ for role in Role.objects.filter(specific_role='dns-recursif-server'):
+ role.specific_role = 'dns-recursive-server'
+ role.save()
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0098_auto_20190102_1745'),
+ ]
+
+ operations = [
+ migrations.RunPython(migrate),
+ ]
+
+
diff --git a/machines/migrations/0100_auto_20190102_1753.py b/machines/migrations/0100_auto_20190102_1753.py
new file mode 100644
index 00000000..35f7b78d
--- /dev/null
+++ b/machines/migrations/0100_auto_20190102_1753.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2019-01-02 23:53
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0099_role_recursive_dns'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='role',
+ name='specific_role',
+ field=models.CharField(blank=True, choices=[('dhcp-server', 'DHCP server'), ('switch-conf-server', 'Switches configuration server'), ('dns-recursive-server', 'Recursive DNS server'), ('ntp-server', 'NTP server'), ('radius-server', 'RADIUS server'), ('log-server', 'Log server'), ('ldap-master-server', 'LDAP master server'), ('ldap-backup-server', 'LDAP backup server'), ('smtp-server', 'SMTP server'), ('postgresql-server', 'postgreSQL server'), ('mysql-server', 'mySQL server'), ('sql-client', 'SQL client'), ('gateway', 'Gateway')], max_length=32, null=True),
+ ),
+ ]
diff --git a/machines/migrations/0101_auto_20190108_1623.py b/machines/migrations/0101_auto_20190108_1623.py
new file mode 100644
index 00000000..856721ac
--- /dev/null
+++ b/machines/migrations/0101_auto_20190108_1623.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2019-01-08 22:23
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0100_auto_20190102_1753'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='ouvertureport',
+ options={'verbose_name': 'ports opening', 'verbose_name_plural': 'ports openings'},
+ ),
+ migrations.AlterField(
+ model_name='nas',
+ name='port_access_mode',
+ field=models.CharField(choices=[('802.1X', '802.1X'), ('Mac-address', 'MAC-address')], default='802.1X', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='vlan',
+ name='igmp',
+ field=models.BooleanField(default=False, help_text='v4 multicast management'),
+ ),
+ migrations.AlterField(
+ model_name='vlan',
+ name='mld',
+ field=models.BooleanField(default=False, help_text='v6 multicast management'),
+ ),
+ ]
diff --git a/machines/models.py b/machines/models.py
index 4de0b012..cdc6d830 100644
--- a/machines/models.py
+++ b/machines/models.py
@@ -27,37 +27,35 @@ The models definitions for the Machines app
from __future__ import unicode_literals
-from datetime import timedelta
+import base64
+import hashlib
import re
+from datetime import timedelta
from ipaddress import IPv6Address
from itertools import chain
-from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress
-import hashlib
-import base64
+from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.models import Q
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.forms import ValidationError
-from django.utils.functional import cached_property
from django.utils import timezone
-from django.core.validators import MaxValueValidator, MinValueValidator
+from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
+from macaddress.fields import MACAddressField, default_dialect
+from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress
-from macaddress.fields import MACAddressField
-
+import preferences.models
+import users.models
from re2o.field_permissions import FieldPermissionModelMixin
from re2o.mixins import AclMixin, RevMixin
-import users.models
-import preferences.models
-
class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
""" Class définissant une machine, object parent user, objets fils
interfaces"""
- user = models.ForeignKey('users.User', on_delete=models.PROTECT)
+ user = models.ForeignKey('users.User', on_delete=models.CASCADE)
name = models.CharField(
max_length=255,
help_text=_("Optional"),
@@ -116,7 +114,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
:return: True ou False avec la raison de l'échec le cas échéant"""
if not user_request.has_perm('machines.view_machine'):
return False, _("You don't have the right to view all the"
- " machines.")
+ " machines.")
return True, None
@staticmethod
@@ -131,9 +129,9 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
except users.models.User.DoesNotExist:
return False, _("Nonexistent user.")
max_lambdauser_interfaces = (preferences.models.OptionalMachine
- .get_cached_value(
- 'max_lambdauser_interfaces'
- ))
+ .get_cached_value(
+ 'max_lambdauser_interfaces'
+ ))
if not user_request.has_perm('machines.add_machine'):
if not (preferences.models.OptionalMachine
.get_cached_value('create_machine')):
@@ -180,7 +178,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
**kwargs
)[0]):
return False, _("You don't have the right to delete a machine"
- " of another user.")
+ " of another user.")
return True, None
def can_view(self, user_request, *_args, **_kwargs):
@@ -192,14 +190,24 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
if (not user_request.has_perm('machines.view_machine') and
self.user != user_request):
return False, _("You don't have the right to view other machines"
- " than yours.")
+ " than yours.")
return True, None
@cached_property
def short_name(self):
"""Par defaut, renvoie le nom de la première interface
de cette machine"""
- return str(self.interface_set.first().domain.name)
+ interfaces_set = self.interface_set.first()
+ if interfaces_set:
+ return str(interfaces_set.domain.name)
+ else:
+ return _("No name")
+
+ @cached_property
+ def complete_name(self):
+ """Par defaut, renvoie le nom de la première interface
+ de cette machine"""
+ return str(self.interface_set.first())
@cached_property
def all_short_names(self):
@@ -207,14 +215,19 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
machine"""
return Domain.objects.filter(
interface_parent__machine=self
- ).values_list('name', flat=True).distinct()
+ ).values_list('name', flat=True).distinct()
+
+ @cached_property
+ def get_name(self):
+ """Return a name : user provided name or first interface name"""
+ return self.name or self.short_name
@cached_property
def all_complete_names(self):
"""Renvoie tous les tls complets de la machine"""
return [str(domain) for domain in Domain.objects.filter(
Q(cname__interface_parent__machine=self) | Q(interface_parent__machine=self)
- )]
+ )]
def __init__(self, *args, **kwargs):
super(Machine, self).__init__(*args, **kwargs)
@@ -290,8 +303,8 @@ class IpType(RevMixin, AclMixin, models.Model):
help_text=_("Netmask for the domain's IPv4 range")
)
reverse_v4 = models.BooleanField(
- default=False,
- help_text=_("Enable reverse DNS for IPv4"),
+ default=False,
+ help_text=_("Enable reverse DNS for IPv4"),
)
prefix_v6 = models.GenericIPAddressField(
protocol='IPv6',
@@ -304,10 +317,10 @@ class IpType(RevMixin, AclMixin, models.Model):
MaxValueValidator(128),
MinValueValidator(0)
]
- )
+ )
reverse_v6 = models.BooleanField(
- default=False,
- help_text=_("Enable reverse DNS for IPv6"),
+ default=False,
+ help_text=_("Enable reverse DNS for IPv6"),
)
vlan = models.ForeignKey(
'Vlan',
@@ -327,7 +340,7 @@ class IpType(RevMixin, AclMixin, models.Model):
("use_all_iptype", _("Can use all IP types")),
)
verbose_name = _("IP type")
- verbose_name_plural = ("IP types")
+ verbose_name_plural = _("IP types")
@cached_property
def ip_range(self):
@@ -367,9 +380,9 @@ class IpType(RevMixin, AclMixin, models.Model):
def ip6_set_full_info(self):
if self.prefix_v6:
return {
- 'network' : str(self.prefix_v6),
- 'netmask' : 'ffff:ffff:ffff:ffff::',
- 'netmask_cidr' : str(self.prefix_v6_length),
+ 'network': str(self.prefix_v6),
+ 'netmask': 'ffff:ffff:ffff:ffff::',
+ 'netmask_cidr': str(self.prefix_v6_length),
'vlan': str(self.vlan),
'vlan_id': self.vlan.vlan_id
}
@@ -388,10 +401,10 @@ class IpType(RevMixin, AclMixin, models.Model):
def ip_net_full_info(self):
"""Renvoie les infos du network contenant du range"""
return {
- 'network' : str(self.ip_network.network),
- 'netmask' : str(self.ip_network.netmask),
- 'broadcast' : str(self.ip_network.broadcast),
- 'netmask_cidr' : str(self.ip_network.prefixlen),
+ 'network': str(self.ip_network.network),
+ 'netmask': str(self.ip_network.netmask),
+ 'broadcast': str(self.ip_network.broadcast),
+ 'netmask_cidr': str(self.ip_network.prefixlen),
}
@cached_property
@@ -442,9 +455,9 @@ class IpType(RevMixin, AclMixin, models.Model):
return
else:
for ipv6 in Ipv6List.objects.filter(
- interface__in=Interface.objects.filter(
- type__in=MachineType.objects.filter(ip_type=self)
- )
+ interface__in=Interface.objects.filter(
+ type__in=MachineType.objects.filter(ip_type=self)
+ )
):
ipv6.check_and_replace_prefix(prefix=self.prefix_v6)
@@ -515,6 +528,18 @@ class Vlan(RevMixin, AclMixin, models.Model):
vlan_id = models.PositiveIntegerField(validators=[MaxValueValidator(4095)])
name = models.CharField(max_length=256)
comment = models.CharField(max_length=256, blank=True)
+ #Réglages supplémentaires
+ arp_protect = models.BooleanField(default=False)
+ dhcp_snooping = models.BooleanField(default=False)
+ dhcpv6_snooping = models.BooleanField(default=False)
+ igmp = models.BooleanField(
+ default=False,
+ help_text=_("v4 multicast management")
+ )
+ mld = models.BooleanField(
+ default=False,
+ help_text=_("v6 multicast management")
+ )
class Meta:
permissions = (
@@ -534,7 +559,7 @@ class Nas(RevMixin, AclMixin, models.Model):
default_mode = '802.1X'
AUTH = (
('802.1X', '802.1X'),
- ('Mac-address', 'Mac-address'),
+ ('Mac-address', _("MAC-address")),
)
name = models.CharField(max_length=255, unique=True)
@@ -641,7 +666,7 @@ class SOA(RevMixin, AclMixin, models.Model):
utilisée dans les migrations de la BDD. """
return cls.objects.get_or_create(
name=_("SOA to edit"),
- mail="postmaser@example.com"
+ mail="postmaster@example.com"
)[0].pk
@@ -671,6 +696,10 @@ class Extension(RevMixin, AclMixin, models.Model):
'SOA',
on_delete=models.CASCADE
)
+ dnssec = models.BooleanField(
+ default=False,
+ help_text=_("Should the zone be signed with DNSSEC")
+ )
class Meta:
permissions = (
@@ -716,6 +745,9 @@ class Extension(RevMixin, AclMixin, models.Model):
.filter(cname__interface_parent__in=all_active_assigned_interfaces())
.prefetch_related('cname'))
+ def get_associated_dname_records(self):
+ return (DName.objects.filter(alias=self))
+
@staticmethod
def can_use_all(user_request, *_args, **_kwargs):
"""Superdroit qui permet d'utiliser toutes les extensions sans
@@ -796,8 +828,8 @@ class Txt(RevMixin, AclMixin, models.Model):
verbose_name_plural = _("TXT records")
def __str__(self):
- return str(self.zone) + " : " + str(self.field1) + " " +\
- str(self.field2)
+ return str(self.zone) + " : " + str(self.field1) + " " + \
+ str(self.field2)
@cached_property
def dns_entry(self):
@@ -856,7 +888,7 @@ class Srv(RevMixin, AclMixin, models.Model):
default=0,
validators=[MaxValueValidator(65535)],
help_text=_("Relative weight for records with the same priority"
- " (integer value between 0 and 65535)")
+ " (integer value between 0 and 65535)")
)
port = models.PositiveIntegerField(
validators=[MaxValueValidator(65535)],
@@ -876,17 +908,17 @@ class Srv(RevMixin, AclMixin, models.Model):
verbose_name_plural = _("SRV records")
def __str__(self):
- return str(self.service) + ' ' + str(self.protocole) + ' ' +\
- str(self.extension) + ' ' + str(self.priority) +\
- ' ' + str(self.weight) + str(self.port) + str(self.target)
+ return str(self.service) + ' ' + str(self.protocole) + ' ' + \
+ str(self.extension) + ' ' + str(self.priority) + \
+ ' ' + str(self.weight) + str(self.port) + str(self.target)
@cached_property
def dns_entry(self):
"""Renvoie l'enregistrement SRV complet pour le fichier de zone"""
- return str(self.service) + '._' + str(self.protocole).lower() +\
- str(self.extension) + '. ' + str(self.ttl) + ' IN SRV ' +\
- str(self.priority) + ' ' + str(self.weight) + ' ' +\
- str(self.port) + ' ' + str(self.target) + '.'
+ return str(self.service) + '._' + str(self.protocole).lower() + \
+ str(self.extension) + '. ' + str(self.ttl) + ' IN SRV ' + \
+ str(self.priority) + ' ' + str(self.weight) + ' ' + \
+ str(self.port) + ' ' + str(self.target) + '.'
class SshFp(RevMixin, AclMixin, models.Model):
@@ -902,7 +934,7 @@ class SshFp(RevMixin, AclMixin, models.Model):
machine = models.ForeignKey('Machine', on_delete=models.CASCADE)
pub_key_entry = models.TextField(
- help_text="SSH public key",
+ help_text=_("SSH public key"),
max_length=2048
)
algo = models.CharField(
@@ -910,7 +942,7 @@ class SshFp(RevMixin, AclMixin, models.Model):
max_length=32
)
comment = models.CharField(
- help_text="Comment",
+ help_text=_("Comment"),
max_length=255,
null=True,
blank=True
@@ -931,8 +963,8 @@ class SshFp(RevMixin, AclMixin, models.Model):
"""Return the hashess for the pub key with correct id
cf RFC, 1 is sha1 , 2 sha256"""
return {
- "1" : hashlib.sha1(base64.b64decode(self.pub_key_entry)).hexdigest(),
- "2" : hashlib.sha256(base64.b64decode(self.pub_key_entry)).hexdigest(),
+ "1": hashlib.sha1(base64.b64decode(self.pub_key_entry)).hexdigest(),
+ "2": hashlib.sha256(base64.b64decode(self.pub_key_entry)).hexdigest(),
}
class Meta:
@@ -955,7 +987,6 @@ class SshFp(RevMixin, AclMixin, models.Model):
return str(self.algo) + ' ' + str(self.comment)
-
class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
""" Une interface. Objet clef de l'application machine :
- une address mac unique. Possibilité de la rendre unique avec le
@@ -1049,7 +1080,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
.get_cached_value('ipv6_mode') == 'SLAAC'):
self.sync_ipv6_slaac()
elif (preferences.models.OptionalMachine
- .get_cached_value('ipv6_mode') == 'DHCPV6'):
+ .get_cached_value('ipv6_mode') == 'DHCPV6'):
self.sync_ipv6_dhcpv6()
else:
return
@@ -1062,10 +1093,10 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
.get_cached_value('ipv6_mode') == 'SLAAC'):
return self.ipv6list.all()
elif (preferences.models.OptionalMachine
- .get_cached_value('ipv6_mode') == 'DHCPV6'):
+ .get_cached_value('ipv6_mode') == 'DHCPV6'):
return self.ipv6list.filter(slaac_ip=False)
else:
- return None
+ return []
def mac_bare(self):
""" Formatage de la mac type mac_bare"""
@@ -1075,28 +1106,10 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
""" Tente un formatage mac_bare, si échoue, lève une erreur de
validation"""
try:
- self.mac_address = str(EUI(self.mac_address))
+ self.mac_address = str(EUI(self.mac_address, dialect=default_dialect()))
except:
raise ValidationError(_("The given MAC address is invalid."))
- def clean(self, *args, **kwargs):
- """ Formate l'addresse mac en mac_bare (fonction filter_mac)
- et assigne une ipv4 dans le bon range si inexistante ou incohérente"""
- # If type was an invalid value, django won't create an attribute type
- # but try clean() as we may be able to create it from another value
- # so even if the error as yet been detected at this point, django
- # continues because the error might not prevent us from creating the
- # instance.
- # But in our case, it's impossible to create a type value so we raise
- # the error.
- if not hasattr(self, 'type'):
- raise ValidationError(_("The selected IP type is invalid."))
- self.filter_macaddress()
- self.mac_address = str(EUI(self.mac_address)) or None
- if not self.ipv4 or self.type.ip_type != self.ipv4.ip_type:
- self.assign_ipv4()
- super(Interface, self).clean(*args, **kwargs)
-
def assign_ipv4(self):
""" Assigne une ip à l'interface """
free_ips = self.type.ip_type.free_ip()
@@ -1116,6 +1129,42 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
self.clean()
self.save()
+ def has_private_ip(self):
+ """ True si l'ip associée est privée"""
+ if self.ipv4:
+ return IPAddress(str(self.ipv4)).is_private()
+ else:
+ return False
+
+ def may_have_port_open(self):
+ """ True si l'interface a une ip et une ip publique.
+ Permet de ne pas exporter des ouvertures sur des ip privées
+ (useless)"""
+ return self.ipv4 and not self.has_private_ip()
+
+ def clean(self, *args, **kwargs):
+ """ Formate l'addresse mac en mac_bare (fonction filter_mac)
+ et assigne une ipv4 dans le bon range si inexistante ou incohérente"""
+ # If type was an invalid value, django won't create an attribute type
+ # but try clean() as we may be able to create it from another value
+ # so even if the error as yet been detected at this point, django
+ # continues because the error might not prevent us from creating the
+ # instance.
+ # But in our case, it's impossible to create a type value so we raise
+ # the error.
+ if not hasattr(self, 'type'):
+ raise ValidationError(_("The selected IP type is invalid."))
+ self.filter_macaddress()
+ if not self.ipv4 or self.type.ip_type != self.ipv4.ip_type:
+ self.assign_ipv4()
+ super(Interface, self).clean(*args, **kwargs)
+
+ def validate_unique(self, *args, **kwargs):
+ super(Interface, self).validate_unique(*args, **kwargs)
+ interfaces_similar = Interface.objects.filter(mac_address=self.mac_address, type__ip_type=self.type.ip_type)
+ if interfaces_similar and interfaces_similar.first() != self:
+ raise ValidationError(_("Mac address already registered in this Machine Type/Subnet"))
+
def save(self, *args, **kwargs):
self.filter_macaddress()
# On verifie la cohérence en forçant l'extension par la méthode
@@ -1123,6 +1172,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if self.type.ip_type != self.ipv4.ip_type:
raise ValidationError(_("The IPv4 address and the machine type"
" don't match."))
+ self.validate_unique()
super(Interface, self).save(*args, **kwargs)
@staticmethod
@@ -1141,9 +1191,9 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
.get_cached_value('create_machine')):
return False, _("You can't add a machine.")
max_lambdauser_interfaces = (preferences.models.OptionalMachine
- .get_cached_value(
- 'max_lambdauser_interfaces'
- ))
+ .get_cached_value(
+ 'max_lambdauser_interfaces'
+ ))
if machine.user != user_request:
return False, _("You don't have the right to add an interface"
" to a machine of another user.")
@@ -1220,19 +1270,6 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
domain = None
return str(domain)
- def has_private_ip(self):
- """ True si l'ip associée est privée"""
- if self.ipv4:
- return IPAddress(str(self.ipv4)).is_private()
- else:
- return False
-
- def may_have_port_open(self):
- """ True si l'interface a une ip et une ip publique.
- Permet de ne pas exporter des ouvertures sur des ip privées
- (useless)"""
- return self.ipv4 and not self.has_private_ip()
-
class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
""" A list of IPv6 """
@@ -1347,10 +1384,13 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
def clean(self, *args, **kwargs):
if self.slaac_ip and (Ipv6List.objects
- .filter(interface=self.interface, slaac_ip=True)
- .exclude(id=self.id)):
+ .filter(interface=self.interface, slaac_ip=True)
+ .exclude(id=self.id)):
raise ValidationError(_("A SLAAC IP address is already registered."))
- prefix_v6 = self.interface.type.ip_type.prefix_v6.encode().decode('utf-8')
+ try:
+ prefix_v6 = self.interface.type.ip_type.prefix_v6.encode().decode('utf-8')
+ except AttributeError: # Prevents from crashing when there is no defined prefix_v6
+ prefix_v6 = None
if prefix_v6:
if (IPv6Address(self.ipv6.encode().decode('utf-8')).exploded[:20] !=
IPv6Address(prefix_v6).exploded[:20]):
@@ -1480,18 +1520,18 @@ class Domain(RevMixin, AclMixin, models.Model):
return False, _("Nonexistent interface.")
if not user_request.has_perm('machines.add_domain'):
max_lambdauser_aliases = (preferences.models.OptionalMachine
- .get_cached_value(
- 'max_lambdauser_aliases'
- ))
+ .get_cached_value(
+ 'max_lambdauser_aliases'
+ ))
if interface.machine.user != user_request:
return False, _("You don't have the right to add an alias to a"
" machine of another user.")
if Domain.objects.filter(
cname__in=Domain.objects.filter(
interface_parent__in=(interface.machine.user
- .user_interfaces())
+ .user_interfaces())
)
- ).count() >= max_lambdauser_aliases:
+ ).count() >= max_lambdauser_aliases:
return False, _("You reached the maximum number of alias that"
" you are allowed to create yourself (%s). "
% max_lambdauser_aliases)
@@ -1579,7 +1619,7 @@ class Role(RevMixin, AclMixin, models.Model):
ROLE = (
('dhcp-server', _("DHCP server")),
('switch-conf-server', _("Switches configuration server")),
- ('dns-recursif-server', _("Recursive DNS server")),
+ ('dns-recursive-server', _("Recursive DNS server")),
('ntp-server', _("NTP server")),
('radius-server', _("RADIUS server")),
('log-server', _("Log server")),
@@ -1608,18 +1648,6 @@ class Role(RevMixin, AclMixin, models.Model):
verbose_name = _("server role")
verbose_name_plural = _("server roles")
- @classmethod
- def get_instance(cls, roleid, *_args, **_kwargs):
- """Get the Role instance with roleid.
-
- Args:
- roleid: The id
-
- Returns:
- The role.
- """
- return cls.objects.get(pk=roleid)
-
@classmethod
def interface_for_roletype(cls, roletype):
"""Return interfaces for a roletype"""
@@ -1634,6 +1662,11 @@ class Role(RevMixin, AclMixin, models.Model):
machine__interface__role=cls.objects.filter(specific_role=roletype)
)
+ @classmethod
+ def interface_for_roletype(cls, roletype):
+ """Return interfaces for a roletype"""
+ return Interface.objects.filter(role=cls.objects.filter(specific_role=roletype))
+
def save(self, *args, **kwargs):
super(Role, self).save(*args, **kwargs)
@@ -1664,7 +1697,7 @@ class Service(RevMixin, AclMixin, models.Model):
def ask_regen(self):
""" Marque à True la demande de régénération pour un service x """
- Service_link.objects.filter(service=self).exclude(asked_regen=True)\
+ Service_link.objects.filter(service=self).exclude(asked_regen=True) \
.update(asked_regen=True)
return
@@ -1672,11 +1705,11 @@ class Service(RevMixin, AclMixin, models.Model):
""" Django ne peut créer lui meme les relations manytomany avec table
intermediaire explicite"""
for serv in servers.exclude(
- pk__in=Interface.objects.filter(service=self)
+ pk__in=Interface.objects.filter(service=self)
):
link = Service_link(service=self, server=serv)
link.save()
- Service_link.objects.filter(service=self).exclude(server__in=servers)\
+ Service_link.objects.filter(service=self).exclude(server__in=servers) \
.delete()
return
@@ -1723,10 +1756,10 @@ class Service_link(RevMixin, AclMixin, models.Model):
régénération de service"""
return bool(
(self.asked_regen and (
- self.last_regen + self.service.min_time_regen
+ self.last_regen + self.service.min_time_regen
) < timezone.now()
- ) or (
- self.last_regen + self.service.regular_time_regen
+ ) or (
+ self.last_regen + self.service.regular_time_regen
) < timezone.now()
)
@@ -1844,10 +1877,10 @@ class OuverturePort(RevMixin, AclMixin, models.Model):
),
default=OUT,
)
-
+
class Meta:
verbose_name = _("ports opening")
- verbose_name = _("ports openings")
+ verbose_name_plural = _("ports openings")
def __str__(self):
if self.begin == self.end:
@@ -2013,4 +2046,3 @@ def srv_post_save(**_kwargs):
def srv_post_delete(**_kwargs):
"""Regeneration dns après modification d'un SRV"""
regen('dns')
-
diff --git a/machines/serializers.py b/machines/serializers.py
index f3a47c55..3f5fb966 100644
--- a/machines/serializers.py
+++ b/machines/serializers.py
@@ -26,8 +26,8 @@
Serializers for the Machines app
"""
-
from rest_framework import serializers
+
from machines.models import (
Interface,
IpType,
@@ -148,13 +148,13 @@ class TypeSerializer(serializers.ModelSerializer):
get ForeignKey values. Infos about the general port policy is added """
extension = ExtensionNameField(read_only=True)
- ouverture_ports_tcp_in = serializers\
+ ouverture_ports_tcp_in = serializers \
.SerializerMethodField('get_port_policy_input_tcp')
- ouverture_ports_tcp_out = serializers\
+ ouverture_ports_tcp_out = serializers \
.SerializerMethodField('get_port_policy_output_tcp')
- ouverture_ports_udp_in = serializers\
+ ouverture_ports_udp_in = serializers \
.SerializerMethodField('get_port_policy_input_udp')
- ouverture_ports_udp_out = serializers\
+ ouverture_ports_udp_out = serializers \
.SerializerMethodField('get_port_policy_output_udp')
class Meta:
@@ -400,7 +400,7 @@ class OuverturePortsSerializer(serializers.Serializer):
return {
i.ipv4.ipv4: {
"tcp_in": [j.tcp_ports_in() for j in i.port_lists.all()],
- "tcp_out": [j.tcp_ports_out()for j in i.port_lists.all()],
+ "tcp_out": [j.tcp_ports_out() for j in i.port_lists.all()],
"udp_in": [j.udp_ports_in() for j in i.port_lists.all()],
"udp_out": [j.udp_ports_out() for j in i.port_lists.all()],
}
@@ -413,7 +413,7 @@ class OuverturePortsSerializer(serializers.Serializer):
return {
i.ipv6: {
"tcp_in": [j.tcp_ports_in() for j in i.port_lists.all()],
- "tcp_out": [j.tcp_ports_out()for j in i.port_lists.all()],
+ "tcp_out": [j.tcp_ports_out() for j in i.port_lists.all()],
"udp_in": [j.udp_ports_in() for j in i.port_lists.all()],
"udp_out": [j.udp_ports_out() for j in i.port_lists.all()],
}
diff --git a/machines/templates/machines/aff_alias.html b/machines/templates/machines/aff_alias.html
index 17266a6e..ee8580b0 100644
--- a/machines/templates/machines/aff_alias.html
+++ b/machines/templates/machines/aff_alias.html
@@ -28,10 +28,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Aliases" %}
-
-
+
+
{% trans "Aliases" %}
+
+
{% for alias in alias_list %}
@@ -45,4 +45,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_dname.html b/machines/templates/machines/aff_dname.html
index 7e043d7c..6d07a7bc 100644
--- a/machines/templates/machines/aff_dname.html
+++ b/machines/templates/machines/aff_dname.html
@@ -26,11 +26,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Target zone" %}
-
{% trans "Record" %}
-
-
+
+
{% trans "Target zone" %}
+
{% trans "Record" %}
+
+
{% for dname in dname_list %}
@@ -45,4 +45,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_extension.html b/machines/templates/machines/aff_extension.html
index 43bb9e39..1083b1b1 100644
--- a/machines/templates/machines/aff_extension.html
+++ b/machines/templates/machines/aff_extension.html
@@ -30,34 +30,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html
index b8ed5293..c30c0c73 100644
--- a/machines/templates/machines/aff_iptype.html
+++ b/machines/templates/machines/aff_iptype.html
@@ -31,36 +31,36 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "IP type" %}
-
{% trans "Extension" %}
-
{% trans "'infra' right required" %}
-
{% trans "IPv4 range" %}
-
{% trans "v6 prefix" %}
-
{% trans "DNSSEC reverse v4/v6" %}
-
{% trans "On VLAN(s)" %}
-
{% trans "Default ports opening" %}
-
-
+
+
{% trans "IP type" %}
+
{% trans "Extension" %}
+
{% trans "'infra' right required" %}
+
{% trans "IPv4 range" %}
+
{% trans "v6 prefix" %}
+
{% trans "DNSSEC reverse v4/v6" %}
+
{% trans "On VLAN(s)" %}
+
{% trans "Default ports opening" %}
+
+
{% for type in iptype_list %}
-
-
{{ type.type }}
-
{{ type.extension }}
-
{{ type.need_infra|tick }}
-
{{ type.domaine_ip_start }}-{{ type.domaine_ip_stop }}{% if type.ip_network %} on {{ type.ip_network }}{% endif %}
+ {% can_edit type %}
+ {% include 'buttons/edit.html' with href='machines:edit-iptype' id=type.id %}
+ {% acl_end %}
+ {% history_button type %}
+
+
{% endfor %}
-
diff --git a/machines/templates/machines/aff_ipv6.html b/machines/templates/machines/aff_ipv6.html
index a98c0327..f67bf4c3 100644
--- a/machines/templates/machines/aff_ipv6.html
+++ b/machines/templates/machines/aff_ipv6.html
@@ -28,12 +28,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "IPv6 addresses" %}
-
{% trans "SLAAC" %}
-
-
-
+
+
{% trans "IPv6 addresses" %}
+
{% trans "SLAAC" %}
+
+
+
{% for ipv6 in ipv6_list %}
{{ ipv6.ipv6 }}
@@ -50,4 +50,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html
index 33ae617a..4363cd6e 100644
--- a/machines/templates/machines/aff_machines.html
+++ b/machines/templates/machines/aff_machines.html
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if machines_list.paginator %}
- {% include "pagination.html" with list=machines_list %}
+ {% include 'pagination.html' with list=machines_list go_to_id="machines" %}
{% endif %}
@@ -41,7 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "DNS name" as tr_dns_name %}
-
{% include "buttons/sort.html" with prefix='machine' col='name' text=tr_dns_name %}
+
{% include 'buttons/sort.html' with prefix='machine' col='name' text=tr_dns_name %}
{% trans "Type" %}
{% trans "MAC address" %}
{% trans "IP address" %}
@@ -52,96 +52,102 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "No name" as tr_no_name %}
{% trans "View the profile" as tr_view_the_profile %}
- {{ machine.name|default:tr_no_name }}
+ {{ machine.get_name|default:tr_no_name }}
{{ machine.user }}
- {% can_create Interface machine.id %}
- {% trans "Create an interface" as tr_create_an_interface %}
- {% include 'buttons/add.html' with href='machines:new-interface' id=machine.id desc=tr_create_an_interface %}
- {% acl_end %}
- {% history_button machine %}
- {% can_delete machine %}
- {% include 'buttons/suppr.html' with href='machines:del-machine' id=machine.id %}
- {% acl_end %}
-
-
- {% for interface in machine.interface_set.all %}
+ {% can_create Interface machine.id %}
+ {% trans "Create an interface" as tr_create_an_interface %}
+ {% include 'buttons/add.html' with href='machines:new-interface' id=machine.id desc=tr_create_an_interface %}
+ {% acl_end %}
+ {% history_button machine %}
+ {% can_delete machine %}
+ {% include 'buttons/suppr.html' with href='machines:del-machine' id=machine.id %}
+ {% acl_end %}
+
+
+ {% for interface in machine.interface_set.all %}
{% if machines_list.paginator %}
- {% include "pagination.html" with list=machines_list %}
+ {% include 'pagination.html' with list=machines_list go_to_id="machines" %}
{% endif %}
-
diff --git a/machines/templates/machines/aff_machinetype.html b/machines/templates/machines/aff_machinetype.html
index 4725ffb8..ebd77b4f 100644
--- a/machines/templates/machines/aff_machinetype.html
+++ b/machines/templates/machines/aff_machinetype.html
@@ -28,11 +28,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Machine type" %}
-
{% trans "Matching IP type" %}
-
-
+
+
{% trans "Machine type" %}
+
{% trans "Matching IP type" %}
+
+
{% for type in machinetype_list %}
@@ -47,4 +47,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_mx.html b/machines/templates/machines/aff_mx.html
index e57e73a4..b10d4eff 100644
--- a/machines/templates/machines/aff_mx.html
+++ b/machines/templates/machines/aff_mx.html
@@ -28,12 +28,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Concerned zone" %}
-
{% trans "Priority" %}
-
{% trans "Record" %}
-
-
+
+
{% trans "Concerned zone" %}
+
{% trans "Priority" %}
+
{% trans "Record" %}
+
+
{% for mx in mx_list %}
@@ -49,4 +49,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_nas.html b/machines/templates/machines/aff_nas.html
index 0dd612cc..7a98a7f4 100644
--- a/machines/templates/machines/aff_nas.html
+++ b/machines/templates/machines/aff_nas.html
@@ -29,19 +29,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Name" %}
-
{% trans "NAS device type" %}
-
{% trans "Machine type linked to the NAS device" %}
-
{% trans "Access mode" %}
-
{% trans "MAC address auto capture" %}
-
-
+
+
{% trans "Name" %}
+
{% trans "NAS device type" %}
+
{% trans "Machine type linked to the NAS device" %}
+
{% trans "Access mode" %}
+
{% trans "MAC address auto capture" %}
+
+
{% for nas in nas_list %}
{{ nas.name }}
-
{{ nas.nas_type }}
+
{{ nas.nas_type }}
{{ nas.machine_type }}
{{ nas.port_access_mode }}
{{ nas.autocapture_mac|tick }}
@@ -54,4 +54,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_ns.html b/machines/templates/machines/aff_ns.html
index e2187e3e..dda578f3 100644
--- a/machines/templates/machines/aff_ns.html
+++ b/machines/templates/machines/aff_ns.html
@@ -28,11 +28,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Concerned zone" %}
-
{% trans "Authoritarian interface for the concerned zone" %}
-
-
+
+
{% trans "Concerned zone" %}
+
{% trans "Authoritarian interface for the concerned zone" %}
+
+
{% for ns in ns_list %}
@@ -47,4 +47,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_role.html b/machines/templates/machines/aff_role.html
index bba094b3..6f285c89 100644
--- a/machines/templates/machines/aff_role.html
+++ b/machines/templates/machines/aff_role.html
@@ -29,13 +29,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Role name" %}
-
{% trans "Specific role" %}
-
{% trans "Servers" %}
-
-
-
+
+
{% trans "Role name" %}
+
{% trans "Specific role" %}
+
{% trans "Servers" %}
+
+
+
{% for role in role_list %}
@@ -43,12 +43,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{{ role.specific_role }}
{% for serv in role.servers.all %}{{ serv }}, {% endfor %}
- {% can_edit role %}
- {% include 'buttons/edit.html' with href='machines:edit-role' id=role.id %}
- {% acl_end %}
- {% history_button role %}
-
-
+ {% can_edit role %}
+ {% include 'buttons/edit.html' with href='machines:edit-role' id=role.id %}
+ {% acl_end %}
+ {% history_button role %}
+
+
{% endfor %}
-
diff --git a/machines/templates/machines/aff_servers.html b/machines/templates/machines/aff_servers.html
index 7dd25495..4134c269 100644
--- a/machines/templates/machines/aff_servers.html
+++ b/machines/templates/machines/aff_servers.html
@@ -27,13 +27,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Service name" %}
-
{% trans "Server" %}
-
{% trans "Last regeneration" %}
-
{% trans "Regeneration required" %}
-
{% trans "Regeneration activated" %}
-
+
+
{% trans "Service name" %}
+
{% trans "Server" %}
+
{% trans "Last regeneration" %}
+
{% trans "Regeneration required" %}
+
{% trans "Regeneration activated" %}
+
{% for server in servers_list %}
@@ -47,4 +47,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_service.html b/machines/templates/machines/aff_service.html
index df04b93c..d3eb16ba 100644
--- a/machines/templates/machines/aff_service.html
+++ b/machines/templates/machines/aff_service.html
@@ -28,14 +28,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Service name" %}
-
{% trans "Minimal time before regeneration" %}
-
{% trans "Maximal time before regeneration" %}
-
{% trans "Included servers" %}
-
{% trans "Ask for regeneration" %}
-
-
+
+
{% trans "Service name" %}
+
{% trans "Minimal time before regeneration" %}
+
{% trans "Maximal time before regeneration" %}
+
{% trans "Included servers" %}
+
{% trans "Ask for regeneration" %}
+
+
{% for service in service_list %}
@@ -43,7 +43,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{{ service.min_time_regen }}
{{ service.regular_time_regen }}
{% for serv in service.servers.all %}{{ serv }}, {% endfor %}
-
+
{% can_edit service %}
{% include 'buttons/edit.html' with href='machines:edit-service' id=service.id %}
@@ -53,4 +54,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_soa.html b/machines/templates/machines/aff_soa.html
index fbf206e0..50a4a5c3 100644
--- a/machines/templates/machines/aff_soa.html
+++ b/machines/templates/machines/aff_soa.html
@@ -28,15 +28,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Name" %}
-
{% trans "Mail" %}
-
{% trans "Refresh" %}
-
{% trans "Retry" %}
-
{% trans "Expire" %}
-
{% trans "TTL" %}
-
-
+
+
{% trans "Name" %}
+
{% trans "Mail" %}
+
{% trans "Refresh" %}
+
{% trans "Retry" %}
+
{% trans "Expire" %}
+
{% trans "TTL" %}
+
+
{% for soa in soa_list %}
@@ -55,4 +55,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_srv.html b/machines/templates/machines/aff_srv.html
index 2ee569e0..1a699b49 100644
--- a/machines/templates/machines/aff_srv.html
+++ b/machines/templates/machines/aff_srv.html
@@ -28,17 +28,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Service" %}
-
{% trans "Protocol" %}
-
{% trans "Extension" %}
-
{% trans "TTL" %}
-
{% trans "Priority" %}
-
{% trans "Weight" %}
-
{% trans "Port" %}
-
{% trans "Target" %}
-
-
+
+
{% trans "Service" %}
+
{% trans "Protocol" %}
+
{% trans "Extension" %}
+
{% trans "TTL" %}
+
{% trans "Priority" %}
+
{% trans "Weight" %}
+
{% trans "Port" %}
+
{% trans "Target" %}
+
+
{% for srv in srv_list %}
@@ -59,4 +59,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_sshfp.html b/machines/templates/machines/aff_sshfp.html
index f684d6a0..ca88d0f4 100644
--- a/machines/templates/machines/aff_sshfp.html
+++ b/machines/templates/machines/aff_sshfp.html
@@ -27,12 +27,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "SSH public key" %}
-
{% trans "Algorithm used" %}
-
{% trans "Comment" %}
-
-
+
+
{% trans "SSH public key" %}
+
{% trans "Algorithm used" %}
+
{% trans "Comment" %}
+
+
{% for sshfp in sshfp_list %}
@@ -52,4 +52,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_txt.html b/machines/templates/machines/aff_txt.html
index 41778cba..3da268ca 100644
--- a/machines/templates/machines/aff_txt.html
+++ b/machines/templates/machines/aff_txt.html
@@ -28,11 +28,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "Concerned zone" %}
-
{% trans "Record" %}
-
-
+
+
{% trans "Concerned zone" %}
+
{% trans "Record" %}
+
+
{% for txt in txt_list %}
@@ -47,4 +47,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/aff_vlan.html b/machines/templates/machines/aff_vlan.html
index 0c1ed053..0b10262b 100644
--- a/machines/templates/machines/aff_vlan.html
+++ b/machines/templates/machines/aff_vlan.html
@@ -29,20 +29,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
-
-
{% trans "ID" %}
-
{% trans "Name" %}
-
{% trans "Comment" %}
-
{% trans "IP ranges" %}
-
-
+
+
{% trans "ID" %}
+
{% trans "Name" %}
+
{% trans "Comment" %}
+
{% trans "IP ranges" %}
+
+
{% for vlan in vlan_list %}
{{ vlan.vlan_id }}
-
{{ vlan.name }}
+
{{ vlan.name }}
{{ vlan.comment }}
-
{% for range in vlan.iptype_set.all %}{{ range }}, {% endfor%}
+
{% for range in vlan.iptype_set.all %}{{ range }}, {% endfor %}
{% can_edit vlan %}
{% include 'buttons/edit.html' with href='machines:edit-vlan' id=vlan.id %}
@@ -53,4 +53,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
-
diff --git a/machines/templates/machines/delete.html b/machines/templates/machines/delete.html
index 1c9811f2..59ba2102 100644
--- a/machines/templates/machines/delete.html
+++ b/machines/templates/machines/delete.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -26,18 +26,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load bootstrap3 %}
{% load i18n %}
-{% block title %}{% trans "Creation and editing of machines" %}{% endblock %}
+{% block title %}{% trans "Deletion of machines" %}{% endblock %}
{% block content %}
-
-
-
-
+
+
+
+
{% endblock %}
-
diff --git a/machines/templates/machines/edit_portlist.html b/machines/templates/machines/edit_portlist.html
index d6a5e9df..fa9f771a 100644
--- a/machines/templates/machines/edit_portlist.html
+++ b/machines/templates/machines/edit_portlist.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -29,44 +29,45 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-{% bootstrap_form_errors port_list %}
+ {% bootstrap_form_errors port_list %}
-
-
+ function add_port() {
+ var new_index = document.getElementsByClassName('port').length;
+ document.getElementById('id_form-TOTAL_FORMS').value =
+ parseInt(document.getElementById('id_form-TOTAL_FORMS').value) + 1;
+ var new_port = document.createElement('div');
+ new_port.className = 'port';
+ new_port.innerHTML = template.replace(/__prefix__/g, new_index);
+ document.getElementById('formset').appendChild(new_port);
+ }
+
+ document.addEventListener("DOMContentLoaded", function () {
+ document.getElementById("add_one").addEventListener("click", add_port, true);
+ });
+
{% endblock %}
-
diff --git a/machines/templates/machines/index.html b/machines/templates/machines/index.html
index 509334a0..3aad6d06 100644
--- a/machines/templates/machines/index.html
+++ b/machines/templates/machines/index.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -29,10 +29,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
{% trans "Machines" %}
- {% include "machines/aff_machines.html" with machines_list=machines_list %}
-
-
-
+
{% trans "Machines" %}
+ {% include 'machines/aff_machines.html' with machines_list=machines_list %}
+
+
+
{% endblock %}
-
diff --git a/machines/templates/machines/index_alias.html b/machines/templates/machines/index_alias.html
index 2d33177f..7f392667 100644
--- a/machines/templates/machines/index_alias.html
+++ b/machines/templates/machines/index_alias.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,11 +30,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
{% trans "List of the aliases of the interface" %}
- {% trans " Add an alias" %}
- {% trans " Delete one or several aliases" %}
- {% include "machines/aff_alias.html" with alias_list=alias_list %}
-
-
-
+ {% trans " Add an alias" %}
+ {% trans " Delete one or several aliases" %}
+ {% include 'machines/aff_alias.html' with alias_list=alias_list %}
+
+
+
{% endblock %}
-
diff --git a/machines/templates/machines/index_extension.html b/machines/templates/machines/index_extension.html
index 6669d197..636b314e 100644
--- a/machines/templates/machines/index_extension.html
+++ b/machines/templates/machines/index_extension.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -24,67 +24,86 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% load bootstrap3 %}
-
{% load acl %}
{% load i18n %}
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
+ {% can_create IpType %}
+
+ {% trans " Add an IP type" %}
+
+ {% acl_end %}
+
+ {% trans " Delete one or several IP types" %}
+
+ {% include 'machines/aff_iptype.html' with iptype_list=iptype_list %}
{% endblock %}
-
diff --git a/machines/templates/machines/index_ipv6.html b/machines/templates/machines/index_ipv6.html
index 06e287e2..98ea697a 100644
--- a/machines/templates/machines/index_ipv6.html
+++ b/machines/templates/machines/index_ipv6.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,13 +30,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
{% trans "List of the IPv6 addresses of the interface" %}
- {% can_create Ipv6List interface_id %}
- {% trans " Add an IPv6 address" %}
- {% acl_end %}
- {% include "machines/aff_ipv6.html" with ipv6_list=ipv6_list %}
-
-
-
+
{% trans "List of the IPv6 addresses of the interface" %}
+ {% can_create Ipv6List interface_id %}
+
+ {% trans " Add an IPv6 address" %}
+
+ {% acl_end %}
+ {% include 'machines/aff_ipv6.html' with ipv6_list=ipv6_list %}
+
+
+
{% endblock %}
-
diff --git a/machines/templates/machines/index_machinetype.html b/machines/templates/machines/index_machinetype.html
index de1e2f58..407aef5b 100644
--- a/machines/templates/machines/index_machinetype.html
+++ b/machines/templates/machines/index_machinetype.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -31,14 +31,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
+ {% can_create MachineType %}
+
+ {% trans " Add a machine type" %}
+
+ {% acl_end %}
+
+ {% trans " Delete one or several machine types" %}
+
+ {% include 'machines/aff_machinetype.html' with machinetype_list=machinetype_list %}
+
+
+
{% endblock %}
-
diff --git a/machines/templates/machines/index_nas.html b/machines/templates/machines/index_nas.html
index 88f68213..bb17395a 100644
--- a/machines/templates/machines/index_nas.html
+++ b/machines/templates/machines/index_nas.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -31,15 +31,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
{% trans "List of NAS devices" %}
-
{% trans "The NAS device type and machine type are linked. It is useful for MAC address auto capture by RADIUS, and allows to choose the machine type to assign to the machines according to the NAS device type." %}
{% trans "The NAS device type and machine type are linked. It is useful for MAC address auto capture by RADIUS, and allows to choose the machine type to assign to the machines according to the NAS device type." %}
+ {% can_create Nas %}
+
+ {% trans " Add a NAS device type" %}
+
+ {% acl_end %}
+
+ {% trans " Delete one or several NAS device types" %}
+
+ {% include 'machines/aff_nas.html' with nas_list=nas_list %}
+
+
+
{% endblock %}
-
diff --git a/machines/templates/machines/index_portlist.html b/machines/templates/machines/index_portlist.html
index 0d3d0741..c540478d 100644
--- a/machines/templates/machines/index_portlist.html
+++ b/machines/templates/machines/index_portlist.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% load bootstrap3 %}
@@ -8,60 +8,58 @@
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
+ {% can_edit pl %}
+ {% include 'buttons/edit.html' with href='machines:edit-portlist' id=pl.id %}
+ {% acl_end %}
+ {% can_delete pl %}
+ {% include 'buttons/suppr.html' with href='machines:del-portlist' id=pl.id %}
+ {% acl_end %}
+
+
+ {% endfor %}
+
{% endblock %}
-
diff --git a/machines/templates/machines/index_role.html b/machines/templates/machines/index_role.html
index ddc2ea8b..38799aa5 100644
--- a/machines/templates/machines/index_role.html
+++ b/machines/templates/machines/index_role.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,13 +30,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
+ {% can_create Role %}
+ {% trans " Add a role" %}
+ {% acl_end %}
+ {% trans " Delete one or several roles" %}
+ {% include 'machines/aff_role.html' with role_list=role_list %}
{% endblock %}
-
diff --git a/machines/templates/machines/index_service.html b/machines/templates/machines/index_service.html
index 9dec7032..19244e71 100644
--- a/machines/templates/machines/index_service.html
+++ b/machines/templates/machines/index_service.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,16 +30,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
+ {% include 'machines/aff_servers.html' with servers_list=servers_list %}
+{% endblock %}
diff --git a/machines/templates/machines/index_sshfp.html b/machines/templates/machines/index_sshfp.html
index ce16d621..c1508eaf 100644
--- a/machines/templates/machines/index_sshfp.html
+++ b/machines/templates/machines/index_sshfp.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -34,6 +34,5 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans " Add an SSH fingerprint" %}
{% acl_end %}
- {% include "machines/aff_sshfp.html" with sshfp_list=sshfp_list %}
+ {% include 'machines/aff_sshfp.html' with sshfp_list=sshfp_list %}
{% endblock %}
-
diff --git a/machines/templates/machines/index_vlan.html b/machines/templates/machines/index_vlan.html
index 7af31fd5..830cde65 100644
--- a/machines/templates/machines/index_vlan.html
+++ b/machines/templates/machines/index_vlan.html
@@ -1,4 +1,4 @@
-{% extends "machines/sidebar.html" %}
+{% extends 'machines/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -24,21 +24,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% load bootstrap3 %}
-
{% load acl %}
{% load i18n %}
{% block title %}{% trans "Machines" %}{% endblock %}
{% block content %}
-
{% trans "This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines accepted by RADIUS'" %}
+
+
+
{% trans "VLAN for machines accepted by RADIUS" %}
+
{% blocktrans with vlan_decision_ok=radiusoptions.vlan_decision_ok %}VLAN {{ vlan_decision_ok }}{% endblocktrans %}
+ {% can_edit reminder %}
+ {% include 'buttons/edit.html' with href='preferences:edit-reminder' id=reminder.id %}
+ {% acl_end %}
+ {% can_delete reminder %}
+ {% include 'buttons/suppr.html' with href='preferences:del-reminder' id=reminder.id %}
+ {% acl_end %}
+ {% history_button reminder %}
+
+
+ {% endfor %}
+
+
+
diff --git a/preferences/templates/preferences/aff_service.html b/preferences/templates/preferences/aff_service.html
index c08e14e0..dce81768 100644
--- a/preferences/templates/preferences/aff_service.html
+++ b/preferences/templates/preferences/aff_service.html
@@ -42,10 +42,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{{ service.description }}
{{ service.image }}
- {% can_edit service%}
- {% include 'buttons/edit.html' with href='preferences:edit-service' id=service.id %}
- {% acl_end %}
- {% history_button service %}
+ {% can_edit service%}
+ {% include 'buttons/edit.html' with href='preferences:edit-service' id=service.id %}
+ {% acl_end %}
+ {% can_delete service %}
+ {% include 'buttons/suppr.html' with href='preferences:del-service' id=service.id %}
+ {% acl_end %}
+ {% history_button service %}
{% trans "This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines accepted by RADIUS'" %}
-
-
-
-
{% trans "VLAN for machines accepted by RADIUS" %}
-
{{ topologieoptions.vlan_decision_ok }}
-
{% trans "VLAN for machines rejected by RADIUS" %}
{% trans "This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines accepted by RADIUS'" %}
+
+
+
+
{% trans "VLAN for machines accepted by RADIUS" %}
+
{{ topologieoptions.vlan_decision_ok }}
+
{% trans "VLAN for machines rejected by RADIUS" %}
+
{{ topologieoptions.vlan_decision_nok }}
+
+
+
{% trans "VLAN for non members machines" %}
+
{{ topologieoptions.vlan_non_member }}
+
+
+
+
{% trans "RADIUS keys" %}
+ {% can_create RadiusKey%}
+ {% trans " Add a RADIUS key" %}
+ {% acl_end %}
+ {% include 'preferences/aff_radiuskey.html' with radiuskey_list=radiuskey_list %}
+
+
{% trans "Email address for automatic emailing" %}
-
{{ generaloptions.email_from }}
-
-
-
{% trans "Number of results displayed when searching" %}
-
{{ generaloptions.search_display_page }}
-
{% trans "Number of items per page (standard size)" %}
-
{{ generaloptions.pagination_number }}
-
-
-
{% trans "Number of items per page (large size)" %}
-
{{ generaloptions.pagination_large_number }}
-
{% trans "Time before expiration of the reset password link (in hours)" %}
-
{{ generaloptions.req_expire_hrs }}
-
-
-
{% trans "General message displayed on the website" %}
-
{{ generaloptions.general_message }}
-
{% trans "Summary of the General Terms of Use" %}
-
{{ generaloptions.GTU_sum_up }}
-
-
-
{% trans "General Terms of Use" %}
-
{{ generaloptions.GTU }}
-
-
-
{% trans "Information about the organisation" %}
+
+
+
+
+
{% trans "Web management, activated in case of automatic provision" %}
+
{{ topologieoptions.switchs_web_management }}
+
{% trans "REST management, activated in case of automatic provision" %}
+
{{ topologieoptions.switchs_rest_management }}
+
+
+
+
+
+
{% if topologieoptions.provision_switchs_enabled %}{% trans "Provision of configuration for switches" %}{% else %}{% trans "Provision of configuration for switches" %}{% endif%}
+
+
+
{% trans "Switches with automatic provision" %}
+
{{ topologieoptions.provisioned_switchs|join:", " }} {% if topologieoptions.provisioned_switchs %}{% trans "OK" %}{% else %}{% trans "Missing" %}{% endif %}
+
+
+
{% trans "IP range for the management of switches" %}
+
{{ topologieoptions.switchs_ip_type }} {% if topologieoptions.switchs_ip_type %}{% trans "OK" %}{% else %}{% trans "Missing" %}{% endif %}
+
+
+
{% trans "Server for the configuration of switches" %}
+
{{ topologieoptions.switchs_management_interface }} {% if topologieoptions.switchs_management_interface %} - {{ topologieoptions.switchs_management_interface_ip }} {% trans "OK" %}{% else %}{% trans "Missing" %}{% endif %}
+
+
+
{% trans "Provision of configuration mode for switches" %}
+
{{ topologieoptions.switchs_provision }}
+
+
+
{% trans "TFTP mode" %}
+
{% trans "OK" %}
+
+
+
{% trans "SFTP mode" %}
+
{% if topologieoptions.switchs_management_sftp_creds %}{% trans "OK" %}{% else %}{% trans "Missing credentials" %}{% endif %}
+ {% if switchmanagementcred_list %}{% trans "OK" %}{% else %}{% trans "Missing" %}{% endif %}
+ {% include 'preferences/aff_switchmanagementcred.html' with switchmanagementcred_list=switchmanagementcred_list %}
+
+ {% can_create preferences.Reminder%}
+
+ {% trans " Add a reminder" %}
+
{% acl_end %}
- {% trans " Delete one or several services" %}
- {% include "preferences/aff_service.html" with service_list=service_list %}
+ {% include 'preferences/aff_reminder.html' with reminder_list=reminder_list %}
+
+
{% endblock %}
diff --git a/preferences/templates/preferences/edit_preferences.html b/preferences/templates/preferences/edit_preferences.html
index 356f2362..b5f8c506 100644
--- a/preferences/templates/preferences/edit_preferences.html
+++ b/preferences/templates/preferences/edit_preferences.html
@@ -1,4 +1,4 @@
-{% extends "preferences/sidebar.html" %}
+{% extends 'preferences/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -36,9 +36,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
diff --git a/preferences/templates/preferences/preferences.html b/preferences/templates/preferences/preferences.html
index e4ad4ba2..308d121e 100644
--- a/preferences/templates/preferences/preferences.html
+++ b/preferences/templates/preferences/preferences.html
@@ -1,4 +1,4 @@
-{% extends "preferences/sidebar.html" %}
+{% extends 'preferences/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load bootstrap3 %}
{% load i18n %}
+{% load massive_bootstrap_form %}
{% block title %}{% trans "Preferences" %}{% endblock %}
@@ -37,9 +38,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% blocktrans trimmed %}
Re2o is an administration tool initiated by
- Rezo Supelec Metz and a few
+ Rezo Metz and a few
members of other FedeRez associations
around the summer 2016.
It is intended to be a tool independant from any network infrastructure
diff --git a/re2o/templates/re2o/contact.html b/re2o/templates/re2o/contact.html
index f26e002b..b20fe875 100644
--- a/re2o/templates/re2o/contact.html
+++ b/re2o/templates/re2o/contact.html
@@ -1,4 +1,4 @@
-{% extends "re2o/sidebar.html" %}
+{% extends 're2o/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
diff --git a/re2o/templates/re2o/history.html b/re2o/templates/re2o/history.html
index 945a355e..d991b033 100644
--- a/re2o/templates/re2o/history.html
+++ b/re2o/templates/re2o/history.html
@@ -1,4 +1,4 @@
-{% extends "re2o/sidebar.html" %}
+{% extends 're2o/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
{% blocktrans %}History of {{ object }}{% endblocktrans %}
- {% include "re2o/aff_history.html" with reversions=reversions %}
+ {% include 're2o/aff_history.html' with reversions=reversions %}
diff --git a/re2o/templates/re2o/index.html b/re2o/templates/re2o/index.html
index f7adacbc..a6b1a8c5 100644
--- a/re2o/templates/re2o/index.html
+++ b/re2o/templates/re2o/index.html
@@ -1,4 +1,4 @@
-{% extends "re2o/sidebar.html" %}
+{% extends 're2o/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -42,7 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Registration" %}
{% trans "If you don't have an account yet and you want to access the Internet and the organisation's services, create your own personal account." %}
diff --git a/re2o/templates/re2o/sidebar.html b/re2o/templates/re2o/sidebar.html
index c9202d14..e7e58599 100644
--- a/re2o/templates/re2o/sidebar.html
+++ b/re2o/templates/re2o/sidebar.html
@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends 'base.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
diff --git a/re2o/templatetags/design.py b/re2o/templatetags/design.py
index c64e9b40..9df37c30 100644
--- a/re2o/templatetags/design.py
+++ b/re2o/templatetags/design.py
@@ -31,9 +31,9 @@ def tick(valeur, autoescape=False):
if isinstance(valeur,bool):
if valeur == True:
- result = ''
+ result = ''
else:
- result = ''
+ result = ''
return mark_safe(result)
else: # if the value is not a boolean, display it as if tick was not called
diff --git a/re2o/utils.py b/re2o/utils.py
index 6f7870f0..20218a81 100644
--- a/re2o/utils.py
+++ b/re2o/utils.py
@@ -38,55 +38,11 @@ from __future__ import unicode_literals
from django.utils import timezone
from django.db.models import Q
-from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from cotisations.models import Cotisation, Facture, Vente
from machines.models import Interface, Machine
from users.models import Adherent, User, Ban, Whitelist
-
-# Mapping of srtftime format for better understanding
-# https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior
-datetime_mapping={
- '%a': '%a',
- '%A': '%A',
- '%w': '%w',
- '%d': 'dd',
- '%b': '%b',
- '%B': '%B',
- '%m': 'mm',
- '%y': 'yy',
- '%Y': 'yyyy',
- '%H': 'HH',
- '%I': 'HH(12h)',
- '%p': 'AMPM',
- '%M': 'MM',
- '%S': 'SS',
- '%f': 'µµ',
- '%z': 'UTC(+/-HHMM)',
- '%Z': 'UTC(TZ)',
- '%j': '%j',
- '%U': 'ww',
- '%W': 'ww',
- '%c': '%c',
- '%x': '%x',
- '%X': '%X',
- '%%': '%%',
-}
-
-
-def convert_datetime_format(format):
- i=0
- new_format = ""
- while i < len(format):
- if format[i] == '%':
- char = format[i:i+2]
- new_format += datetime_mapping.get(char, char)
- i += 2
- else:
- new_format += format[i]
- i += 1
- return new_format
-
+from preferences.models import AssoOption
def all_adherent(search_time=None):
""" Fonction renvoyant tous les users adherents. Optimisee pour n'est
@@ -103,7 +59,7 @@ def all_adherent(search_time=None):
vente__in=Vente.objects.filter(
facture__in=Facture.objects.all().exclude(valid=False)
)
- ).filter(date_end__gt=search_time)
+ ).filter(Q(date_start__lt=search_time) & Q(date_end__gt=search_time))
)
)
).distinct()
@@ -115,7 +71,7 @@ def all_baned(search_time=None):
search_time = timezone.now()
return User.objects.filter(
ban__in=Ban.objects.filter(
- date_end__gt=search_time
+ Q(date_start__lt=search_time) & Q(date_end__gt=search_time)
)
).distinct()
@@ -126,20 +82,23 @@ def all_whitelisted(search_time=None):
search_time = timezone.now()
return User.objects.filter(
whitelist__in=Whitelist.objects.filter(
- date_end__gt=search_time
+ Q(date_start__lt=search_time) & Q(date_end__gt=search_time)
)
).distinct()
def all_has_access(search_time=None):
- """ Renvoie tous les users beneficiant d'une connexion
- : user adherent ou whiteliste et non banni """
+ """ Return all connected users : active users and whitelisted +
+ asso_user defined in AssoOption pannel
+ ----
+ Renvoie tous les users beneficiant d'une connexion
+ : user adherent et whiteliste non banni plus l'utilisateur asso"""
if search_time is None:
search_time = timezone.now()
- return User.objects.filter(
+ filter_user = (
Q(state=User.STATE_ACTIVE) &
- ~Q(ban__in=Ban.objects.filter(date_end__gt=search_time)) &
- (Q(whitelist__in=Whitelist.objects.filter(date_end__gt=search_time)) |
+ ~Q(ban__in=Ban.objects.filter(Q(date_start__lt=search_time) & Q(date_end__gt=search_time))) &
+ (Q(whitelist__in=Whitelist.objects.filter(Q(date_start__lt=search_time) & Q(date_end__gt=search_time))) |
Q(facture__in=Facture.objects.filter(
vente__in=Vente.objects.filter(
cotisation__in=Cotisation.objects.filter(
@@ -148,10 +107,14 @@ def all_has_access(search_time=None):
facture__in=Facture.objects.all()
.exclude(valid=False)
)
- ).filter(date_end__gt=search_time)
+ ).filter(Q(date_start__lt=search_time) & Q(date_end__gt=search_time))
)
)))
- ).distinct()
+ )
+ asso_user = AssoOption.get_cached_value('utilisateur_asso')
+ if asso_user:
+ filter_user |= Q(id=asso_user.id)
+ return User.objects.filter(filter_user).distinct()
def filter_active_interfaces(interface_set):
@@ -203,164 +166,6 @@ def all_active_assigned_interfaces_count():
return all_active_interfaces_count().filter(ipv4__isnull=False)
-class SortTable:
- """ Class gathering uselful stuff to sort the colums of a table, according
- to the column and order requested. It's used with a dict of possible
- values and associated model_fields """
-
- # All the possible possible values
- # The naming convention is based on the URL or the views function
- # The syntax to describe the sort to apply is a dict where the keys are
- # the url value and the values are a list of model field name to use to
- # order the request. They are applied in the order they are given.
- # A 'default' might be provided to specify what to do if the requested col
- # doesn't match any keys.
-
- USERS_INDEX = {
- 'user_name': ['name'],
- 'user_surname': ['surname'],
- 'user_pseudo': ['pseudo'],
- 'user_room': ['room'],
- 'default': ['state', 'pseudo']
- }
- USERS_INDEX_BAN = {
- 'ban_user': ['user__pseudo'],
- 'ban_start': ['date_start'],
- 'ban_end': ['date_end'],
- 'default': ['-date_end']
- }
- USERS_INDEX_WHITE = {
- 'white_user': ['user__pseudo'],
- 'white_start': ['date_start'],
- 'white_end': ['date_end'],
- 'default': ['-date_end']
- }
- USERS_INDEX_SCHOOL = {
- 'school_name': ['name'],
- 'default': ['name']
- }
- MACHINES_INDEX = {
- 'machine_name': ['name'],
- 'default': ['pk']
- }
- COTISATIONS_INDEX = {
- 'cotis_user': ['user__pseudo'],
- 'cotis_paiement': ['paiement__moyen'],
- 'cotis_date': ['date'],
- 'cotis_id': ['id'],
- 'default': ['-date']
- }
- COTISATIONS_CUSTOM = {
- 'invoice_date': ['date'],
- 'invoice_id': ['id'],
- 'invoice_recipient': ['recipient'],
- 'invoice_address': ['address'],
- 'invoice_payment': ['payment'],
- 'default': ['-date']
- }
- COTISATIONS_CONTROL = {
- 'control_name': ['user__adherent__name'],
- 'control_surname': ['user__surname'],
- 'control_paiement': ['paiement'],
- 'control_date': ['date'],
- 'control_valid': ['valid'],
- 'control_control': ['control'],
- 'control_id': ['id'],
- 'control_user-id': ['user__id'],
- 'default': ['-date']
- }
- TOPOLOGIE_INDEX = {
- 'switch_dns': ['interface__domain__name'],
- 'switch_ip': ['interface__ipv4__ipv4'],
- 'switch_loc': ['switchbay__name'],
- 'switch_ports': ['number'],
- 'switch_stack': ['stack__name'],
- 'default': ['switchbay', 'stack', 'stack_member_id']
- }
- TOPOLOGIE_INDEX_PORT = {
- 'port_port': ['port'],
- 'port_room': ['room__name'],
- 'port_interface': ['machine_interface__domain__name'],
- 'port_related': ['related__switch__name'],
- 'port_radius': ['radius'],
- 'port_vlan': ['vlan_force__name'],
- 'default': ['port']
- }
- TOPOLOGIE_INDEX_ROOM = {
- 'room_name': ['name'],
- 'default': ['name']
- }
- TOPOLOGIE_INDEX_BUILDING = {
- 'building_name': ['name'],
- 'default': ['name']
- }
- TOPOLOGIE_INDEX_BORNE = {
- 'ap_name': ['interface__domain__name'],
- 'ap_ip': ['interface__ipv4__ipv4'],
- 'ap_mac': ['interface__mac_address'],
- 'default': ['interface__domain__name']
- }
- TOPOLOGIE_INDEX_STACK = {
- 'stack_name': ['name'],
- 'stack_id': ['stack_id'],
- 'default': ['stack_id'],
- }
- TOPOLOGIE_INDEX_MODEL_SWITCH = {
- 'model-switch_name': ['reference'],
- 'model-switch_contructor': ['constructor__name'],
- 'default': ['reference'],
- }
- TOPOLOGIE_INDEX_SWITCH_BAY = {
- 'switch-bay_name': ['name'],
- 'switch-bay_building': ['building__name'],
- 'default': ['name'],
- }
- TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH = {
- 'constructor-switch_name': ['name'],
- 'default': ['name'],
- }
- LOGS_INDEX = {
- 'sum_date': ['revision__date_created'],
- 'default': ['-revision__date_created'],
- }
- LOGS_STATS_LOGS = {
- 'logs_author': ['user__name'],
- 'logs_date': ['date_created'],
- 'default': ['-date_created']
- }
-
- @staticmethod
- def sort(request, col, order, values):
- """ Check if the given values are possible and add .order_by() and
- a .reverse() as specified according to those values """
- fields = values.get(col, None)
- if not fields:
- fields = values.get('default', [])
- request = request.order_by(*fields)
- if values.get(col, None) and order == 'desc':
- return request.reverse()
- else:
- return request
-
-
-def re2o_paginator(request, query_set, pagination_number):
- """Paginator script for list display in re2o.
- :request:
- :query_set: Query_set to paginate
- :pagination_number: Number of entries to display"""
- paginator = Paginator(query_set, pagination_number)
- page = request.GET.get('page')
- try:
- results = paginator.page(page)
- except PageNotAnInteger:
- # If page is not an integer, deliver first page.
- results = paginator.page(1)
- except EmptyPage:
- # If page is out of range (e.g. 9999), deliver last page of results.
- results = paginator.page(paginator.num_pages)
- return results
-
-
def remove_user_room(room):
""" Déménage de force l'ancien locataire de la chambre """
try:
@@ -370,18 +175,3 @@ def remove_user_room(room):
user.room = None
user.save()
-
-def get_input_formats_help_text(input_formats):
- """Returns a help text about the possible input formats"""
- if len(input_formats) > 1:
- help_text_template="Format: {main} {more}"
- else:
- help_text_template="Format: {main}"
- more_text_template=""
- help_text = help_text_template.format(
- main=convert_datetime_format(input_formats[0]),
- more=more_text_template.format(
- '\n'.join(map(convert_datetime_format, input_formats))
- )
- )
- return help_text
diff --git a/re2o/views.py b/re2o/views.py
index 15becb35..0ff2774b 100644
--- a/re2o/views.py
+++ b/re2o/views.py
@@ -84,7 +84,7 @@ def about_page(request):
git_info_commit = last_commit.hexsha
git_info_commit_date = last_commit.committed_datetime
except:
- NO_GIT_MSG = _("Unable to get the information")
+ NO_GIT_MSG = _("Unable to get the information.")
git_info_remote = NO_GIT_MSG
git_info_branch = NO_GIT_MSG
git_info_commit = NO_GIT_MSG
diff --git a/search/forms.py b/search/forms.py
index 6065e799..a32c8abc 100644
--- a/search/forms.py
+++ b/search/forms.py
@@ -27,12 +27,13 @@ from __future__ import unicode_literals
from django import forms
from django.forms import Form
from django.utils.translation import ugettext_lazy as _
-from re2o.utils import get_input_formats_help_text
+from re2o.base import get_input_formats_help_text
CHOICES_USER = (
('0', _("Active")),
('1', _("Disabled")),
('2', _("Archived")),
+ ('3', _("Not yet active")),
)
CHOICES_AFF = (
diff --git a/search/locale/fr/LC_MESSAGES/django.mo b/search/locale/fr/LC_MESSAGES/django.mo
deleted file mode 100644
index 94a44104..00000000
Binary files a/search/locale/fr/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/search/locale/fr/LC_MESSAGES/django.po b/search/locale/fr/LC_MESSAGES/django.po
index dd0b63a3..be2a79cc 100644
--- a/search/locale/fr/LC_MESSAGES/django.po
+++ b/search/locale/fr/LC_MESSAGES/django.po
@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-08-15 18:15+0200\n"
+"POT-Creation-Date: 2019-01-08 23:56+0100\n"
"PO-Revision-Date: 2018-06-24 20:10+0200\n"
"Last-Translator: Laouen Fernet \n"
"Language-Team: \n"
@@ -42,44 +42,48 @@ msgstr "Désactivés"
msgid "Archived"
msgstr "Archivés"
-#: forms.py:39
+#: forms.py:36
+msgid "Not yet active"
+msgstr "Pas encore adhéré"
+
+#: forms.py:40
msgid "Users"
msgstr "Utilisateurs"
-#: forms.py:40
+#: forms.py:41
msgid "Machines"
msgstr "Machines"
-#: forms.py:41
+#: forms.py:42
msgid "Invoices"
msgstr "Factures"
-#: forms.py:42
+#: forms.py:43
msgid "Bans"
msgstr "Bannissements"
-#: forms.py:43
+#: forms.py:44
msgid "Whitelists"
msgstr "Accès gracieux"
-#: forms.py:44
+#: forms.py:45
msgid "Rooms"
msgstr "Chambres"
-#: forms.py:45
+#: forms.py:46
msgid "Ports"
msgstr "Ports"
-#: forms.py:46
+#: forms.py:47
msgid "Switches"
msgstr "Commutateurs réseau"
-#: forms.py:59 forms.py:71 templates/search/search.html:29
+#: forms.py:60 forms.py:72 templates/search/search.html:29
#: templates/search/search.html:48
msgid "Search"
msgstr "Rechercher"
-#: forms.py:61 forms.py:73
+#: forms.py:62 forms.py:74
msgid ""
"Use « » and «,» to specify distinct words, «\"query\"» for an exact search "
"and «\\» to escape a character."
@@ -87,19 +91,19 @@ msgstr ""
"Utilisez « » et «,» pour spécifier différents mots, «\"query\"» pour une "
"recherche exacte et «\\» pour échapper un caractère."
-#: forms.py:80
+#: forms.py:81
msgid "Users filter"
msgstr "Filtre utilisateurs"
-#: forms.py:87
+#: forms.py:88
msgid "Display filter"
msgstr "Filtre affichage"
-#: forms.py:95
+#: forms.py:96
msgid "Start date"
msgstr "Date de début"
-#: forms.py:99
+#: forms.py:100
msgid "End date"
msgstr "Date de fin"
@@ -136,11 +140,11 @@ msgid "Results among rooms:"
msgstr "Résultats parmi les chambres :"
#: templates/search/index.html:61
-msgid "Results among ports"
+msgid "Results among ports:"
msgstr "Résultats parmi les ports :"
#: templates/search/index.html:65
-msgid "Results among switches"
+msgid "Results among switches:"
msgstr "Résultats parmi les commutateurs réseau :"
#: templates/search/index.html:69
diff --git a/search/templates/search/index.html b/search/templates/search/index.html
index 23b57cce..4d3e2942 100644
--- a/search/templates/search/index.html
+++ b/search/templates/search/index.html
@@ -1,4 +1,4 @@
-{% extends "search/sidebar.html" %}
+{% extends 'search/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -31,39 +31,39 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
{% if users %}
{% trans "Results among users:" %}
- {% include "users/aff_users.html" with users_list=users %}
+ {% include 'users/aff_users.html' with users_list=users %}
{% endif%}
{% if clubs %}
{% trans "Results among clubs:" %}
- {% include "users/aff_clubs.html" with clubs_list=clubs %}
+ {% include 'users/aff_clubs.html' with clubs_list=clubs %}
{% endif%}
{% if machines %}
{% trans "Results among machines:" %}
- {% include "machines/aff_machines.html" with machines_list=machines %}
+ {% include 'machines/aff_machines.html' with machines_list=machines %}
{% endif %}
{% if factures %}
{% trans "Results among invoices:" %}
- {% include "cotisations/aff_cotisations.html" with facture_list=factures %}
+ {% include 'cotisations/aff_cotisations.html' with facture_list=factures %}
{% endif %}
{% if whitelists %}
{% trans "Results among whitelists:" %}
- {% include "users/aff_whitelists.html" with white_list=whitelists %}
+ {% include 'users/aff_whitelists.html' with white_list=whitelists %}
{% endif %}
{% if bans %}
{% trans "Results among bans:" %}
- {% include "users/aff_bans.html" with ban_list=bans %}
+ {% include 'users/aff_bans.html' with ban_list=bans %}
{% endif %}
{% if rooms %}
{% trans "Results among rooms:" %}
- {% include "topologie/aff_chambres.html" with room_list=rooms %}
+ {% include 'topologie/aff_chambres.html' with room_list=rooms %}
{% endif %}
{% if ports %}
-
{% trans "Results among ports" %}
- {% include "topologie/aff_port.html" with port_list=ports %}
+
{% trans "Results among ports:" %}
+ {% include 'topologie/aff_port.html' with port_list=ports search=True %}
{% endif %}
{% if switches %}
-
{% trans "Results among switches" %}
- {% include "topologie/aff_switch.html" with switch_list=switches %}
+
{% trans "Results among switches:" %}
+ {% include 'topologie/aff_switch.html' with switch_list=switches %}
{% endif %}
{% if not users and not machines and not factures and not whitelists and not bans and not rooms and not ports and not switches %}
{% trans "No result" %}
diff --git a/search/templates/search/search.html b/search/templates/search/search.html
index 42012339..d957a4cf 100644
--- a/search/templates/search/search.html
+++ b/search/templates/search/search.html
@@ -1,4 +1,4 @@
-{% extends "search/sidebar.html" %}
+{% extends 'search/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -34,10 +34,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
+ {% trans "Social networks" %} +
+{% trans "List of contact email addresses" %}
- {% can_create preferences.MailContact %} - {% trans "Add an address" %} - {% acl_end %} - {% trans "Delete one or several addresses" %} - {% include "preferences/aff_mailcontact.html" with mailcontact_list=mailcontact_list %} --
-